Merge "Eliminate unused heap bitmap functions.  This is mostly the "list" code which is no longer needed." into dalvik-dev
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..b84e1b6
--- /dev/null
+++ b/CleanSpec.mk
@@ -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.
+#
+
+# 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 $(PRODUCT_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_DIR) 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_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/libcore-disabled/NOTICE b/libcore-disabled/NOTICE
deleted file mode 100644
index a0a06da..0000000
--- a/libcore-disabled/NOTICE
+++ /dev/null
@@ -1,16 +0,0 @@
-   =========================================================================
-   ==  NOTICE file corresponding to the section 4 d of                    ==
-   ==  the Apache License, Version 2.0,                                   ==
-   ==  in this case for the Apache Harmony distribution.                  ==
-   =========================================================================
-
-Apache Harmony
-Copyright 2006 The Apache Software Foundation
-
-This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
-
-Portions of Harmony were originally developed by
-Intel Corporation and are licensed to the Apache Software
-Foundation under the "Software Grant and Corporate Contribution
-License Agreement", informally known as the "Intel Harmony CLA".
diff --git a/libcore-disabled/SoundTest/Android.mk b/libcore-disabled/SoundTest/Android.mk
deleted file mode 100644
index bd628a5..0000000
--- a/libcore-disabled/SoundTest/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_JAVA_LIBRARIES := framework core
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-#define all-core-resource-dirs
-#$(shell cd $(LOCAL_PATH) && find resources)
-#endef
-
-#LOCAL_JAVA_RESOURCE_DIRS := $(call all-core-resource-dirs)
-
-LOCAL_PACKAGE_NAME := SoundTest
-
-include $(BUILD_PACKAGE)
diff --git a/libcore-disabled/SoundTest/AndroidManifest.xml b/libcore-disabled/SoundTest/AndroidManifest.xml
deleted file mode 100644
index 6c8d257..0000000
--- a/libcore-disabled/SoundTest/AndroidManifest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.tests.soundtest">
- -      <application>
-       <!-- icon="@drawable/logo" -->
-        <activity android:name="SoundTest" android:label="SoundTest">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT"/>
-                <category android:name="android.intent.category.LAUNCHER"/>
-            </intent-filter>
-        </activity>
-    </application> 
-</manifest>
diff --git a/libcore-disabled/SoundTest/assets/fx_foghorn.mp3 b/libcore-disabled/SoundTest/assets/fx_foghorn.mp3
deleted file mode 100644
index 71226cf..0000000
--- a/libcore-disabled/SoundTest/assets/fx_foghorn.mp3
+++ /dev/null
Binary files differ
diff --git a/libcore-disabled/SoundTest/res/layout/riproaring_activity.xml b/libcore-disabled/SoundTest/res/layout/riproaring_activity.xml
deleted file mode 100644
index a21599e..0000000
--- a/libcore-disabled/SoundTest/res/layout/riproaring_activity.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content">
-	<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" />
-		
-	<TextView android:id="@+id/label" android:textStyle="bold" android:textColor="#00000000" android:textSize="16sp" 
-		android:layout_weight="1"
-		android:text="@string/textview_text" />
-		
-	<EditText android:id="@+id/entry" 
-        android:layout_width="match_parent" 
-        android:layout_height="wrap_content" 
-        android:background="@android:drawable/editbox_background"
-        android:text="@string/edittext_text"
-        android:layout_below="@id/label"/>
-  
-    <Button android:id="@+id/ok" 
-        android:layout_width="wrap_content" 
-        android:layout_height="wrap_content" 
-        android:layout_below="@id/entry"
-        android:layout_alignParentRight="true"
-        android:text="@string/button_text" />
-		
-</LinearLayout>
diff --git a/libcore-disabled/SoundTest/res/values/strings.xml b/libcore-disabled/SoundTest/res/values/strings.xml
deleted file mode 100644
index 6ad4891..0000000
--- a/libcore-disabled/SoundTest/res/values/strings.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2007 The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
--->
-
-<resources>
-
-    <string name="textview_text">I am a TextView</string>
-    <string name="edittext_text">I am an EditText</string>
-    <string name="button_text">I am a Button</string>
-
-</resources>
diff --git a/libcore-disabled/SoundTest/src/com/android/tests/soundtest/SoundTest.java b/libcore-disabled/SoundTest/src/com/android/tests/soundtest/SoundTest.java
deleted file mode 100644
index 3be10a0..0000000
--- a/libcore-disabled/SoundTest/src/com/android/tests/soundtest/SoundTest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tests.soundtest;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.HandlerInterface;
-import android.os.Message;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.Button;
-import android.widget.LinearLayout;
-
-import java.io.InputStream;
-
-import javax.sound.midi.MidiSystem;
-import javax.sound.midi.Sequencer;
-import javax.sound.sampled.AudioFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.AudioSystem;
-import javax.sound.sampled.DataLine;
-import javax.sound.sampled.SourceDataLine;
-
-
-public class SoundTest extends Activity implements HandlerInterface {
-
-    public Context mContext;
-    private LinearLayout mLinearLayout;
-    public LayoutParams mParams;
-    Button button, button2;
-
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        Window wp = getWindow();
-        mContext = wp.getContext();
-        mParams = wp.getAttributes();
-
-        mLinearLayout = new LinearLayout(this);
-        mLinearLayout.setOrientation(LinearLayout.VERTICAL);
-        setContentView(mLinearLayout);
-
-        button = new Button(mContext);
-        button.setMinimumWidth(300);
-        button.setMinimumHeight(70);
-        button.setTextSize(14);
-        button.setText("Play sample");
-        button.setOnClickListener(buttonListener);
-
-        mLinearLayout.addView(button, new LinearLayout.LayoutParams(
-            ViewGroup.LayoutParams.WRAP_CONTENT,
-            ViewGroup.LayoutParams.WRAP_CONTENT));
-        
-        button2 = new Button(mContext);
-        button2.setMinimumWidth(300);
-        button2.setMinimumHeight(70);
-        button2.setTextSize(14);
-        button2.setText("Play MIDI");
-        button2.setOnClickListener(buttonListener2);
-
-        mLinearLayout.addView(button2, new LinearLayout.LayoutParams(
-            ViewGroup.LayoutParams.WRAP_CONTENT,
-            ViewGroup.LayoutParams.WRAP_CONTENT));
-        
-    }
-
-    private OnClickListener buttonListener = new OnClickListener() {
-        public void onClick(View v) {
-            try {
-                button.setText(button.getText() + ".");
-                
-                int RENDER_BUFF_SIZE = 1024*48;
-
-                InputStream is = getAssets().open("fx_foghorn.mp3");
-                
-                AudioInputStream ais = null;
-
-                ais = AudioSystem.getAudioInputStream(is);
-
-                AudioFormat af = ais.getFormat();
-                SourceDataLine sdl = null;
-                DataLine.Info dli = new DataLine.Info(SourceDataLine.class, af);
-                sdl = (SourceDataLine)AudioSystem.getLine(dli);
-
-                sdl.open(af);
-                sdl.start();
-
-                int bytesReaded = 0;
-                byte samplesBuff[] = new byte[RENDER_BUFF_SIZE];
-
-                while (bytesReaded != -1) {
-                    bytesReaded = ais.read(samplesBuff, 0, samplesBuff.length);
-                    if (bytesReaded > 0) {
-                        sdl.write(samplesBuff, 0, bytesReaded);
-                    }
-                }
-
-                sdl.drain();
-                sdl.close();
-            } catch (Exception ee) {
-                ee.printStackTrace();
-            }
-        }
-    };
-
-    private OnClickListener buttonListener2 = new OnClickListener() {
-        public void onClick(View v) {
-            try {
-                button2.setText(button2.getText() + ".");
-                
-                int RENDER_BUFF_SIZE = 1024*48;
-
-                InputStream is = getAssets().open("Dancing_Queen.mid");
-                
-                Sequencer s = MidiSystem.getSequencer(); 
-                s.open();
-                s.setSequence(is);
-                s.setLoopCount(1);
-                s.start();
-                
-            } catch (Exception ee) {
-                ee.printStackTrace();
-            }
-        }
-    };
-    
-    public void handleMessage(Message arg0) {
-    }
-}
diff --git a/libcore-disabled/instrument/MODULE_LICENSE_APACHE2 b/libcore-disabled/instrument/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/libcore-disabled/instrument/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/ClassDefinition.java b/libcore-disabled/instrument/src/main/java/java/lang/instrument/ClassDefinition.java
deleted file mode 100644
index 0780ca0..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/ClassDefinition.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/* 
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.instrument;
-
-import org.apache.harmony.instrument.internal.nls.Messages;
-
-/**
- * Wraps a {@link java.lang.Class} that is to be redefined together with the
- * byte array which constitutes the updated version of the class.
- * 
- */
-public final class ClassDefinition {
-
-    /**
-     * The <code>Class</code> object for the class that will be instrumented.
-     */
-    private Class<?> definitionClass;
-
-    /**
-     * The new version of the class file bytes for the class being instrumented.
-     */
-    private byte[] definitionClassFile;
-
-    /**
-     * Constructs a new instance of <code>ClassDefinition</code> with the
-     * supplied {@link Class} object and byte array representing the new class
-     * file bytes.
-     * 
-     * @param theClass
-     *            the <code>Class</code> object for the class to be redefined
-     * @param theClassFile
-     *            an array of bytes containing the updated version of the class
-     *            to be redefined.
-     * @throws NullPointerException
-     *             if either <code>theClass</code> or
-     *             <code>theClassFile</code> are <code>null</code>.
-     */
-    public ClassDefinition(Class<?> theClass, byte[] theClassFile) {
-        if (theClass == null) {
-            throw new NullPointerException(Messages.getString("instrument.1")); //$NON-NLS-1$
-        }
-        if (theClassFile == null) {
-            throw new NullPointerException(Messages.getString("instrument.2")); //$NON-NLS-1$
-        }
-        this.definitionClass = theClass;
-        this.definitionClassFile = theClassFile;
-    }
-
-    /**
-     * Returns the {@link Class} object for the class to be redefined.
-     * 
-     * @return the <code>Class</code> object
-     */
-    public Class<?> getDefinitionClass() {
-        return this.definitionClass;
-    }
-
-    /**
-     * Returns a reference to the byte array containing the re-engineered
-     * version of the class.
-     * 
-     * @return byte array containing the new version of the class
-     */
-    public byte[] getDefinitionClassFile() {
-        return this.definitionClassFile;
-    }
-}
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/ClassFileTransformer.java b/libcore-disabled/instrument/src/main/java/java/lang/instrument/ClassFileTransformer.java
deleted file mode 100644
index 429184d..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/ClassFileTransformer.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/* 
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.instrument;
-
-import java.security.ProtectionDomain;
-
-/**
- * This interface must be implemented by types used to instrument classes as
- * they are loaded by a running VM. Implementations are registered by agents in
- * the {@link java.lang.instrument.Instrumentation#addTransformer} operation.
- * Once registered, a <code>ClassFileTransformer</code> has the opportunity to
- * instrument every class that is loaded or redefined by the VM provided that
- * the transformer does not have a dependency on that class.
- * <p>
- * Transformations of classes takes place just prior to them being defined by
- * the VM.
- * </p>
- * 
- */
-public interface ClassFileTransformer {
-
-    /**
-     * Receives a <code>byte</code> array containing the raw contents of a
-     * class for <i>possible</i> transformation into a new <code>byte</code>
-     * array which gets returned to the caller. It is left up to the
-     * implementation to decide what, if any, transformations are carried out
-     * and returned.
-     * <p>
-     * Requests for class transformations can occur in two situations.
-     * <ul>
-     * <li>the attempted defining of a class using
-     * {@link ClassLoader#defineClass(java.lang.String, byte[], int, int)}
-     * <li>the attempted re-defining of a previously defined class using
-     * {@link Instrumentation#redefineClasses(ClassDefinition[])}
-     * </ul>
-     * In both cases this operation will be called before the verification of
-     * the specified bytes in the <code>Class</code> file format. Each
-     * registered <code>ClassFileTransformer</code> instance will have this
-     * operation called on it. The order of the invocations matches the order in
-     * which the transformers were registered using the method
-     * {@link Instrumentation#addTransformer(ClassFileTransformer)}.
-     * </p>
-     * <p>
-     * Provided that the implementation of this method wishes to carry out a
-     * transformation, the return is a newly allocated <code>byte</code> array
-     * which contains <i>a copy of</i> the <code>classfileBuffer</code>
-     * argument plus the transformations to the array specific to the method
-     * implementation. If the transformer is written so as to pass on the
-     * opportunity to modify a given input then the return value should be
-     * <code>null</code>.
-     * </p>
-     * 
-     * @param loader
-     *            the <i>defining</i> <code>ClassLoader</code> for the
-     *            candidate class to be transformed.
-     * @param className
-     *            the fully qualified name of the candidate class to be
-     *            transformed in the <i>fully/qualified/Name</i> format.
-     * @param classBeingRedefined
-     *            if a class redefinition is in process then this argument will
-     *            be the <code>Class</code> object for the class. Otherwise,
-     *            if a class definition is in process, a <code>null</code>.
-     * @param protectionDomain
-     *            the security protection domain for the class being defined or
-     *            redefined.
-     * @param classfileBuffer
-     *            a <code>byte</code> array containing the class to be
-     *            transformed in <code>Class</code> file format.
-     *            <em>This argument
-     *            must not be modified</em>.
-     * @return if transformation occurs, a newly allocated <code>byte</code>
-     *         array containing the modified version of
-     *         <code>classfileBuffer</code>, otherwise <code>null</code>.
-     * @throws IllegalClassFormatException
-     *             if the <code>classfileBuffer</code> does not contain a
-     *             well-formed representation of a class in the
-     *             <code>Class</code> file format. Note that if an invocation
-     *             of this operation ends on an exception throw then (a) the
-     *             remaining transformers in the &quot;chain&quot; will still
-     *             have this method called, and (b) the class definition or
-     *             redefinition that was the catalyst for the transformation
-     *             opportunities will still be attempted.
-     */
-    public byte[] transform(ClassLoader loader, String className,
-            Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
-            byte[] classfileBuffer) throws IllegalClassFormatException;
-}
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/IllegalClassFormatException.java b/libcore-disabled/instrument/src/main/java/java/lang/instrument/IllegalClassFormatException.java
deleted file mode 100644
index 9696bfe..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/IllegalClassFormatException.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/* 
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.instrument;
-
-/**
- * This exception may be thrown from implementations of the method
- * {@link java.lang.instrument.ClassFileTransformer#transform} when the class
- * file bytes supplied to it are found to be corrupted or otherwise in a format
- * which does not adhere to the expected Java class file format.
- * 
- */
-public class IllegalClassFormatException extends Exception {
-
-    private static final long serialVersionUID = -3841736710924794009L;
-
-    /**
-     * Constructs a new instance of <code>IllegalClassFormatException</code>
-     * with no explanatory message.
-     */
-    public IllegalClassFormatException() {
-        super();
-    }
-
-    /**
-     * Constructs a new instance of <code>IllegalClassFormatException</code>
-     * with the supplied message, <code>s</code>, for explanation.
-     * 
-     * @param s
-     *            a string containing information on why the exception is being
-     *            created.
-     */
-    public IllegalClassFormatException(String s) {
-        super(s);
-    }
-}
\ No newline at end of file
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/Instrumentation.java b/libcore-disabled/instrument/src/main/java/java/lang/instrument/Instrumentation.java
deleted file mode 100644
index 6dd053f..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/Instrumentation.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/* 
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.instrument;
-
-/**
- * Instances of this interface may be used by Java instrumentation agent code
- * for support in carrying out the runtime instrumentation of classes. Using
- * such an approach, classes may be enhanced with services such as profiling,
- * logging or tracing which were not included in the source of the original
- * class.
- * <p>
- * A concrete instance of this interface is made available as an input argument
- * to all Java instrumentation agents'
- * <code>premain(String agentArgs, Instrumentation inst)</code> method.
- * </p>
- * 
- */
-public interface Instrumentation {
-
-    /**
-     * Registers the supplied <code>transformer</code> argument with the VM.
-     * Any classes that are to be defined or re-defined (if supported) in the VM
-     * will then be offered to the transformer for it to carry out any byte code
-     * modifications. The exception to this scheme is if the class to be defined /
-     * re-defined is a dependency of the transformer.
-     * <p>
-     * This operation can be carried out multiple times on a concrete
-     * <code>Instrumentation</code>. The order of registration is important
-     * as it defines the order in which the transformers' transformation
-     * operation gets called.
-     * <p>
-     * <p>
-     * It is possible for any given instance of
-     * <code>ClassFileTransformer</code> to be registered more than once with
-     * this operation.
-     * 
-     * @param transformer
-     *            a class file transformer
-     * @throws NullPointerException
-     *             if <code>transformer</code> is <code>null</code>.
-     */
-    public void addTransformer(ClassFileTransformer transformer);
-
-    /**
-     * Returns an array of all of the classes that have been loaded into the VM.
-     * 
-     * @return an array of <code>Class</code> objects with each element
-     *         identifying a class that has been loaded into the VM.
-     */
-    public Class[] getAllLoadedClasses();
-
-    /**
-     * Returns an array of all of the classes for which <code>loader</code> is
-     * the <i>initiating</i> class loader.
-     * 
-     * @param loader
-     *            a class loader. In order to obtain the array of classes
-     *            initiated by the bootstrap class loader this argument should
-     *            be <code>null</code>.
-     * @return an array of <code>Class</code> objects with each element
-     *         identifying a class that has been initiated by the specified
-     *         class loader.
-     */
-    public Class[] getInitiatedClasses(ClassLoader loader);
-
-    /**
-     * Returns the number of bytes in memory required by this VM for the
-     * supplied object <code>objectToSize</code>. The returned value should
-     * be taken as an estimation only which is susceptible to change between
-     * separate launches of the VM.
-     * 
-     * @param objectToSize
-     *            any object
-     * @return an approximation of the number of bytes in memory taken up by
-     *         <code>objectToSize</code>.
-     * @throws NullPointerException
-     *             if the given object is null.
-     */
-    public long getObjectSize(Object objectToSize);
-
-    /**
-     * Returns a boolean indication of whether or not this VM supports the
-     * on-the-fly redefining of classes that have been already loaded.
-     * 
-     * @return <code>true</code> if class redefining is supported, otherwise
-     *         <code>false</code>.
-     */
-    public boolean isRedefineClassesSupported();
-
-    /**
-     * Receives an array of {@link ClassDefinition} instances and attempts to
-     * carry out on-the-fly redefining on each of the associated classes.
-     * Redefining in this manner may be used to update the following parts of an
-     * already loaded class:
-     * <ul>
-     * <li>attributes
-     * <li>constant pool
-     * <li>method implementations
-     * </ul>
-     * If any invocations of a redefined method are already active in the VM
-     * when this call is made then they will run to completion and be unaffected
-     * by the outcome of this method. Provided the method redefinition is
-     * successful, all subsequent calls on the method will run the new version.
-     * <br>
-     * Redefining a class may <em>not</em> be used to make changes to any
-     * other aspects of a previously loaded class such as its inheritance
-     * hierarchy, the names or signatures of any of its methods, the names of
-     * any fields, the values of any static variables etc.
-     * <p>
-     * If a class associated with a <code>ClassDefinition</code> is
-     * successfully redefined then there will be no resulting re-run of any of
-     * its initialization code. Similarly, any instances of the class that were
-     * created before the redefining will not be changed in any way. That is,
-     * they will remain in the VM as instances of the previous version of the
-     * class.
-     * </p>
-     * <p>
-     * Note that before the requested redefinitions are attempted, each
-     * {@link ClassFileTransformer} registered with the VM will be given the
-     * opportunity to carry out their own custom transformations of the new
-     * version of the class.
-     * </p>
-     * 
-     * @param definitions
-     *            an array of <code>ClassDefinition</code> objects wrapping
-     *            the details of the classes to be redefined. A zero-length
-     *            array value will not cause an error but, instead, will
-     *            silently do nothing.
-     * @throws ClassNotFoundException
-     *             if any of the classes specified in the contents of
-     *             <code>definitions</code> cannot be located.
-     * @throws UnmodifiableClassException
-     *             if any of the classes specified in the contents of
-     *             <code>definitions</code> cannot be modified.
-     * @throws UnsupportedOperationException
-     *             if this method is not supported in by the VM. May be checked
-     *             in advance by calling {@link #isRedefineClassesSupported()}.
-     * @throws ClassFormatError
-     *             if any of the <code>definitions</code> elements has been
-     *             created with a <code>byte</code> array containing a badly
-     *             formed class file.
-     * @throws NoClassDefFoundError
-     *             if there is disagreement between the name of a class to be
-     *             redefined and the name of the class from the corresponding
-     *             class file format byte array.
-     * @throws UnsupportedClassVersionError
-     *             if the version of any of the classes to be redefined is not
-     *             supported by the VM.
-     * @throws ClassCircularityError
-     *             if a circular dependency is detected among the classes to be
-     *             redefined.
-     * @throws LinkageError
-     *             if a linkage error situation is detected such that there is
-     *             an incompatability between dependent classes.
-     * @throws NullPointerException
-     *             if <code>definitions</code> or any of its elements are
-     *             found to be <code>null</code>.
-     * @see #isRedefineClassesSupported()
-     */
-    public void redefineClasses(ClassDefinition[] definitions)
-            throws ClassNotFoundException, UnmodifiableClassException;
-
-    /**
-     * Removes <i>the most recently added instance of</i> the
-     * <code>ClassFileTransformer</code> object from the VM's list of
-     * registered transformers. After this call completes, the specified
-     * <code>ClassFileTransformer</code> object will no longer have its
-     * <code>transform()<code> method automatically invoked when class definitions or
-     * redefinitions are attempted. 
-     * 
-     * @param transformer
-     *            a previously registered <code>ClassFileTransformer</code>.
-     * @return <code>true</code> if <code>transformer</code> was located in
-     *         the list of registered transformers and successfully removed.
-     *         Otherwise, <code>false</code>.
-     * @throws NullPointerException
-     *            if <code>transformer</code> is <code>null</code>.
-     */
-    public boolean removeTransformer(ClassFileTransformer transformer);
-}
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/UnmodifiableClassException.java b/libcore-disabled/instrument/src/main/java/java/lang/instrument/UnmodifiableClassException.java
deleted file mode 100644
index e8c8d57..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/UnmodifiableClassException.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/* 
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.instrument;
-
-/**
- * This exception may be thrown from implementations of the method
- * {@link java.lang.instrument.Instrumentation#redefineClasses} when one of the
- * desired class redefinition operations cannot be carried out. Such a situation
- * may arise if a redefinition attempts to alter the members of a class or its
- * inheritance hierarchy.
- * 
- */
-public class UnmodifiableClassException extends Exception {
-
-    private static final long serialVersionUID = 1716652643585309178L;
-
-    /**
-     * Constructs a new instance of <code>UnmodifiableClassException</code>
-     * with no explanatory message.
-     */
-    public UnmodifiableClassException() {
-        super();
-    }
-
-    /**
-     * Constructs a new instance of <code>UnmodifiableClassException</code>
-     * with the supplied message, <code>s</code>, for explanation.
-     * 
-     * @param s
-     *            a string containing information on why the exception is being
-     *            created.
-     */
-    public UnmodifiableClassException(String s) {
-        super(s);
-    }
-}
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/package.html b/libcore-disabled/instrument/src/main/java/java/lang/instrument/package.html
deleted file mode 100644
index 50224d7..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/package.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
-  <body>
-    <p>
-      Provides classes and interfaces needed for instrumenting applications.
-    <p>
-  </body>
-</html>
\ No newline at end of file
diff --git a/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/Messages.java b/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/Messages.java
deleted file mode 100644
index cdde768..0000000
--- a/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/Messages.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/* 
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
- * All changes made to this file manually will be overwritten 
- * if this tool runs again. Better make changes in the template file.
- */
-
-package org.apache.harmony.instrument.internal.nls;
-
-// BEGIN android-added
-import org.apache.harmony.luni.util.MsgHelp;
-// END android-added
-
-/**
- * This class retrieves strings from a resource bundle and returns them,
- * formatting them with MessageFormat when required.
- * <p>
- * It is used by the system classes to provide national language support, by
- * looking up messages in the <code>
- *    org.apache.harmony.instrument.internal.nls.messages
- * </code>
- * resource bundle. Note that if this file is not available, or an invalid key
- * is looked up, or resource bundle support is not available, the key itself
- * will be returned as the associated message. This means that the <em>KEY</em>
- * should a reasonable human-readable (english) string.
- * 
- */
-public class Messages {
-
-    // BEGIN android-changed
-    private static final String sResource =
-        "org.apache.harmony.instrument.internal.nls.messages";
-    // END android-changed
-
-    /**
-     * Retrieves a message which has no arguments.
-     * 
-     * @param msg
-     *            String the key to look up.
-     * @return String the message for that key in the system message bundle.
-     */
-    static public String getString(String msg) {
-        // BEGIN android-changed
-        return MsgHelp.getString(sResource, msg);
-        // END android-changed
-    }
-
-    /**
-     * Retrieves a message which takes 1 argument.
-     * 
-     * @param msg
-     *            String the key to look up.
-     * @param arg
-     *            Object the object to insert in the formatted output.
-     * @return String the message for that key in the system message bundle.
-     */
-    static public String getString(String msg, Object arg) {
-        return getString(msg, new Object[] { arg });
-    }
-
-    /**
-     * Retrieves a message which takes 1 integer argument.
-     * 
-     * @param msg
-     *            String the key to look up.
-     * @param arg
-     *            int the integer to insert in the formatted output.
-     * @return String the message for that key in the system message bundle.
-     */
-    static public String getString(String msg, int arg) {
-        return getString(msg, new Object[] { Integer.toString(arg) });
-    }
-
-    /**
-     * Retrieves a message which takes 1 character argument.
-     * 
-     * @param msg
-     *            String the key to look up.
-     * @param arg
-     *            char the character to insert in the formatted output.
-     * @return String the message for that key in the system message bundle.
-     */
-    static public String getString(String msg, char arg) {
-        return getString(msg, new Object[] { String.valueOf(arg) });
-    }
-
-    /**
-     * Retrieves a message which takes 2 arguments.
-     * 
-     * @param msg
-     *            String the key to look up.
-     * @param arg1
-     *            Object an object to insert in the formatted output.
-     * @param arg2
-     *            Object another object to insert in the formatted output.
-     * @return String the message for that key in the system message bundle.
-     */
-    static public String getString(String msg, Object arg1, Object arg2) {
-        return getString(msg, new Object[] { arg1, arg2 });
-    }
-
-    /**
-     * Retrieves a message which takes several arguments.
-     * 
-     * @param msg
-     *            String the key to look up.
-     * @param args
-     *            Object[] the objects to insert in the formatted output.
-     * @return String the message for that key in the system message bundle.
-     */
-    static public String getString(String msg, Object[] args) {
-        // BEGIN android-changed
-        return MsgHelp.getString(sResource, msg, args);
-        // END android-changed
-    }
-}
diff --git a/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/messages.properties b/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/messages.properties
deleted file mode 100644
index 6c59186..0000000
--- a/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/messages.properties
+++ /dev/null
@@ -1,21 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#  
-#      http://www.apache.org/licenses/LICENSE-2.0
-#  
-#  Unless required by applicable law or agreed to in writing, software
-#  distributed under the License is distributed on an "AS IS" BASIS,
-#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#  See the License for the specific language governing permissions and
-#  limitations under the License.
-# 
-
-# messages for EN locale
-instrument.1=Received null class argument.
-instrument.2=Received null class file argument.
-instrument.3=Redefinition operation is not supported!
-instrument.4=Fatal error: failed to execute premain class of java agent.
diff --git a/libcore-disabled/sound/MODULE_LICENSE_APACHE2 b/libcore-disabled/sound/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/libcore-disabled/sound/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidMidiFileReader.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidMidiFileReader.java
deleted file mode 100644
index fb6b0e5..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidMidiFileReader.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.midi;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.MidiFileFormat;
-import javax.sound.midi.Sequence;
-import javax.sound.midi.spi.MidiFileReader;
-
-/**
- * Implements a MidiFileReader for Android. We need to cache data coming from an
- * arbitrary InputStream, since the Android MediaPlayer expects us to pass in a
- * file or a URL.
- */
-public class AndroidMidiFileReader extends MidiFileReader {
-
-    @Override
-    public MidiFileFormat getMidiFileFormat(File file) throws InvalidMidiDataException, IOException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public MidiFileFormat getMidiFileFormat(InputStream stream) throws InvalidMidiDataException,
-            IOException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public MidiFileFormat getMidiFileFormat(URL url) throws InvalidMidiDataException, IOException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public Sequence getSequence(File file) throws InvalidMidiDataException, IOException {
-        return new AndroidSequence(file.toURL());
-    }
-
-    @Override
-    public Sequence getSequence(InputStream stream) throws InvalidMidiDataException, IOException {
-        File file = File.createTempFile("javax.sound.midi-", null);
-        file.deleteOnExit();
-
-        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
-        byte[] buffer = new byte[1024];
-
-        int count = stream.read(buffer);
-        while (count >= 0) {
-            out.write(buffer, 0, count);
-            count = stream.read(buffer);
-        }
-
-        out.flush();
-        out.close();
-
-        return getSequence(file);
-    }
-
-    @Override
-    public Sequence getSequence(URL url) throws InvalidMidiDataException, IOException {
-        return new AndroidSequence(url);
-    }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequence.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequence.java
deleted file mode 100644
index 861f970..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequence.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.midi;
-
-import java.net.URL;
-
-import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.Sequence;
-
-/**
- * Implements a MIDI Sequence for Android. Its set of tracks etc. will always
- * be empty (at least we don't care about the contents). Instead, we store the
- * URL to the original MIDI data in it, so we can feed it into the Android
- * MediaPlayer.
- */
-public class AndroidSequence extends Sequence {
-
-    /**
-     * Holds the URL to the MIDI data.
-     */
-    private URL url;
-    
-    /**
-     * Creates a new AndroidSequence.
-     * 
-     * @param url The URL that points to the MIDI data.
-     *  
-     * @throws InvalidMidiDataException If the MIDI data is invalid (which we
-     *         actually don't check at all).
-     */
-    public AndroidSequence(URL url) throws InvalidMidiDataException {
-        super(0.0f, 1);
-        
-        this.url = url;
-    }
-
-    /**
-     * Returns the URL pointing to the MIDI data.
-     * 
-     * @return The URL.
-     */
-    URL getURL() {
-        return url;
-    }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequencer.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequencer.java
deleted file mode 100644
index 6b3ea20..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequencer.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.midi;
-
-import android.media.AudioManager;
-import android.media.MediaPlayer;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.sound.midi.ControllerEventListener;
-import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.MetaEventListener;
-import javax.sound.midi.MidiDevice;
-import javax.sound.midi.MidiUnavailableException;
-import javax.sound.midi.Receiver;
-import javax.sound.midi.Sequence;
-import javax.sound.midi.Sequencer;
-import javax.sound.midi.Track;
-import javax.sound.midi.Transmitter;
-
-/**
- * Implements a MIDI Sequencer for Android. Since Android's MediaPlayer is
- * somewhat limited, we only support MIDI playback, but not recording or the
- * querying of MIDI information. Many of the methods hence throw
- * {@link java.lang.UnsupportedOperationException} or return dummy results.
- */
-public class AndroidSequencer implements Sequencer {
-
-    /**
-     * Defines the DeviceInfo for our AndroidSequencer.
-     */
-    private class Info extends MidiDevice.Info {
-        public Info() {
-            super("Android Sequencer", "Android Sequencer", "The Android Project", "1.0");        
-        }
-    }
-    
-    /**
-     * Holds the Android MediaPlayer we use.
-     */
-    private MediaPlayer player;
-    
-    /**
-     * Holds the Android Sequence we want to play.
-     */
-    private AndroidSequence sequence;
-
-    public int[] addControllerEventListener(ControllerEventListener listener, int[] controllers) {
-        throw new UnsupportedOperationException();
-    }
-
-    public boolean addMetaEventListener(MetaEventListener listener) {
-        throw new UnsupportedOperationException();
-    }
-
-    public int getLoopCount() {
-        throw new UnsupportedOperationException();
-    }
-
-    public long getLoopEndPoint() {
-        throw new UnsupportedOperationException();
-    }
-
-    public long getLoopStartPoint() {
-        throw new UnsupportedOperationException();
-    }
-
-    public SyncMode getMasterSyncMode() {
-        throw new UnsupportedOperationException();
-    }
-
-    public SyncMode[] getMasterSyncModes() {
-        throw new UnsupportedOperationException();
-    }
-
-    public long getMicrosecondLength() {
-        throw new UnsupportedOperationException();
-    }
-
-    public long getMicrosecondPosition() {
-        throw new UnsupportedOperationException();
-    }
-
-    public Sequence getSequence() {
-        return sequence;
-    }
-
-    public SyncMode getSlaveSyncMode() {
-        throw new UnsupportedOperationException();
-    }
-
-    public SyncMode[] getSlaveSyncModes() {
-        throw new UnsupportedOperationException();
-    }
-
-    public float getTempoFactor() {
-        throw new UnsupportedOperationException();
-    }
-
-    public float getTempoInBPM() {
-        throw new UnsupportedOperationException();
-    }
-
-    public float getTempoInMPQ() {
-        throw new UnsupportedOperationException();
-    }
-
-    public long getTickLength() {
-        throw new UnsupportedOperationException();
-    }
-
-    public long getTickPosition() {
-        throw new UnsupportedOperationException();
-    }
-
-    public boolean getTrackMute(int track) {
-        throw new UnsupportedOperationException();
-    }
-
-    public boolean getTrackSolo(int track) {
-        throw new UnsupportedOperationException();
-    }
-
-    public boolean isRecording() {
-        return false;
-    }
-
-    public boolean isRunning() {
-        return player != null && player.isPlaying();
-    }
-
-    public void recordDisable(Track track) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void recordEnable(Track track, int channel) {
-        throw new UnsupportedOperationException();
-    }
-
-    public int[] removeControllerEventListener(ControllerEventListener listener, int[] controllers) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void removeMetaEventListener(MetaEventListener listener) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setLoopCount(int count) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setLoopEndPoint(long tick) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setLoopStartPoint(long tick) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setMasterSyncMode(SyncMode sync) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setMicrosecondPosition(long microseconds) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setSequence(InputStream stream) throws IOException, InvalidMidiDataException {
-        setSequence(new AndroidMidiFileReader().getSequence(stream));
-    }
-
-    public void setSequence(Sequence sequence) throws InvalidMidiDataException {
-        if (!(sequence instanceof AndroidSequence)) {
-            throw new InvalidMidiDataException("Sequence must be an AndroidSequence");
-        }
-        
-        if (isRunning()) {
-            stop();
-        }
-        
-        this.sequence = (AndroidSequence)sequence;
-    }
-
-    public void setSlaveSyncMode(SyncMode sync) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setTempoFactor(float factor) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setTempoInBPM(float bpm) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setTempoInMPQ(float mpq) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setTickPosition(long tick) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setTrackMute(int track, boolean mute) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setTrackSolo(int track, boolean solo) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void start() {
-        if (!isOpen()) {
-            throw new IllegalStateException("Sequencer must be open");
-        }
-        
-        if (sequence == null) {
-            throw new IllegalStateException("Need a Sequence to play");
-        }
-
-        if (!isRunning()) {
-            /*
-             * This is ugly, but there is no way around it: The javax.sound API
-             * doesn't expect to throw an exception at this point for illegal
-             * MIDI sequences. Since we don't really construct the MIDI sequence
-             * from the original binary data, but only refer to its URL, the
-             * MediaPlayer can actually bail out at this point. We wrap the
-             * exception into a RuntimeException, to at least keep the API
-             * contract.
-             */
-            try {
-                String s = this.sequence.getURL().toExternalForm();
-                
-                /*
-                 * TODO Workaround for 1107794: MediaPlayer doesn't handle
-                 * "file:" URLs. Get rid of this.
-                 */
-                if (s.startsWith("file:")) {
-                    s = s.substring(5);
-                }
-                
-                player.setDataSource(s);
-                player.setAudioStreamType(AudioManager.STREAM_MUSIC);
-                player.prepare();
-            } catch (IOException ex) {
-                throw new RuntimeException(ex.toString());
-            }
-            
-            player.start();
-        }
-    }
-
-    public void startRecording() {
-        throw new UnsupportedOperationException();
-    }
-
-    public void stop() {
-        if (!isOpen()) {
-            throw new IllegalStateException("Sequencer must be open");
-        }
-        
-        if (isRunning()) {
-            player.stop();
-        }
-    }
-
-    public void stopRecording() {
-        throw new UnsupportedOperationException();
-    }
-
-    public void close() {
-        if (isOpen()) {
-            stop();
-            player = null;
-        }
-    }
-    
-    public Info getDeviceInfo() {
-        return new Info();
-    }
-
-    public int getMaxReceivers() {
-        return 0;
-    }
-
-    public int getMaxTransmitters() {
-        return 0;
-    }
-
-    public Receiver getReceiver() throws MidiUnavailableException {
-        throw new MidiUnavailableException("No receiver available");
-    }
-
-    public List<Receiver> getReceivers() {
-        return new ArrayList<Receiver>();
-    }
-
-    public Transmitter getTransmitter() throws MidiUnavailableException {
-        throw new MidiUnavailableException("No receiver available");
-    }
-
-    public List<Transmitter> getTransmitters() {
-        return new ArrayList<Transmitter>();
-    }
-
-    public boolean isOpen() {
-        return player != null;
-    }
-
-    public void open() throws MidiUnavailableException {
-        try {
-            player = new MediaPlayer();
-        } catch (Exception ex) {
-            throw new MidiUnavailableException(ex.toString());
-        }
-    }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioFileReader.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioFileReader.java
deleted file mode 100644
index f9b1d47..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioFileReader.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.sampled;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import javax.sound.sampled.AudioFileFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.UnsupportedAudioFileException;
-import javax.sound.sampled.spi.AudioFileReader;
-
-/**
- * Implements an AudioFileReader for Android. We need to cache data coming from
- * an arbitrary InputStream, since the Android MediaPlayer expects us to pass in
- * a file or URL.
- */
-public class AndroidAudioFileReader extends AudioFileReader {
-
-    @Override
-    public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException,
-            IOException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public AudioFileFormat getAudioFileFormat(InputStream stream)
-            throws UnsupportedAudioFileException, IOException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException,
-            IOException {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException,
-            IOException {
-        return new AndroidAudioInputStream(file.toURL());
-    }
-
-    @Override
-    public AudioInputStream getAudioInputStream(InputStream stream)
-            throws UnsupportedAudioFileException, IOException {
-        File file = File.createTempFile("javax.sound.sampled-", null);
-        file.deleteOnExit();
-
-        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
-        byte[] buffer = new byte[1024];
-
-        int count = stream.read(buffer);
-        while (count >= 0) {
-            out.write(buffer, 0, count);
-            count = stream.read(buffer);
-        }
-
-        out.flush();
-        out.close();
-
-        return getAudioInputStream(file);
-    }
-
-    @Override
-    public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException,
-            IOException {
-        return new AndroidAudioInputStream(url);
-    }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioInputStream.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioInputStream.java
deleted file mode 100644
index ba97021..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioInputStream.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.sampled;
-
-import java.net.URL;
-
-import javax.sound.sampled.AudioFormat;
-import javax.sound.sampled.AudioInputStream;
-
-/**
- * Implements an AudioInputStream for Android. Its internal InputStream is
- * unused (at least we don't care about the contents). Instead, we store the
- * URL to the original audio data in it, so we can feed it into the Android
- * MediaPlayer.
- */
-public class AndroidAudioInputStream extends AudioInputStream {
-
-    /**
-     * Holds the URL to the MIDI data.
-     */
-    private URL url;
-    
-    /**
-     * Creates a new AndroidAudioInputStream.
-     * 
-     * @param url The URL that points to the audio data.
-     */
-    public AndroidAudioInputStream(URL url) {
-        super(null, new AudioFormat(0.0f, 0, 0, false, false), 0);
-        
-        this.url = url;
-    }
-
-    /**
-     * Returns the URL pointing to the audio data.
-     * 
-     * @return The URL.
-     */
-    URL getURL() {
-        return url;
-    }
- 
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidClip.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidClip.java
deleted file mode 100644
index d70eec1..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidClip.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.sampled;
-
-import android.media.AudioManager;
-import android.media.MediaPlayer;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.sound.sampled.AudioFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.Clip;
-import javax.sound.sampled.Control;
-import javax.sound.sampled.Line;
-import javax.sound.sampled.LineListener;
-import javax.sound.sampled.LineUnavailableException;
-import javax.sound.sampled.Control.Type;
-
-/**
- * Implements an audio Clip for Android. Since Android's MediaPlayer is somewhat
- * limited, we only support sample playback, but not recording or the querying
- * of sample information. Many of the methods hence throw
- * {@link java.lang.UnsupportedOperationException} or return dummy results.
- */
-public class AndroidClip implements Clip {
-
-    /**
-     * Holds the Android MediaPlayer we use.
-     */
-    private MediaPlayer player;
-    
-    /**
-     * Holds the AndroidAudioInputStream we want to play.
-     */
-    private AndroidAudioInputStream stream;
-    
-    public int getFrameLength() {
-        throw new UnsupportedOperationException();
-    }
-
-    public long getMicrosecondLength() {
-        throw new UnsupportedOperationException();
-    }
-
-    public void loop(int count) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void open(AudioFormat format, byte[] data, int offset, int bufferSize)
-            throws LineUnavailableException {
-        InputStream stream = new ByteArrayInputStream(data, offset, bufferSize);
-
-        open();
-        
-        try {
-            this.stream = (AndroidAudioInputStream)(new AndroidAudioFileReader().getAudioInputStream(stream));
-        } catch (Exception ex) {
-            throw new LineUnavailableException(ex.toString());
-        }
-    }
-
-    public void open(AudioInputStream stream) throws LineUnavailableException, IOException {
-        open();
-        
-        if (!(stream instanceof AndroidAudioInputStream)) {
-            try {
-                stream = new AndroidAudioFileReader().getAudioInputStream(stream);
-            } catch (Exception ex) {
-                throw new LineUnavailableException(ex.toString());
-            }
-        }
-        
-        this.stream = (AndroidAudioInputStream)stream;
-    }
-
-    public void setFramePosition(int frames) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setLoopPoints(int start, int end) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void setMicrosecondPosition(long microseconds) {
-        if (!isOpen()) {
-            throw new IllegalStateException("Clip must be open");
-        }
-        
-        player.seekTo((int)(microseconds / 1000));
-    }
-
-    public int available() {
-        throw new UnsupportedOperationException();
-    }
-
-    public void drain() {
-    }
-
-    public void flush() {
-    }
-
-    public int getBufferSize() {
-        throw new UnsupportedOperationException();
-    }
-
-    public AudioFormat getFormat() {
-        throw new UnsupportedOperationException();
-    }
-
-    public int getFramePosition() {
-        throw new UnsupportedOperationException();
-    }
-
-    public float getLevel() {
-        throw new UnsupportedOperationException();
-    }
-
-    public long getLongFramePosition() {
-        throw new UnsupportedOperationException();
-    }
-
-    public long getMicrosecondPosition() {
-        if (isOpen()) {
-            return player.getCurrentPosition() * 1000;
-        } else {
-            return 0;
-        }
-    }
-
-    public boolean isActive() {
-        return false;
-    }
-
-    public boolean isRunning() {
-        return player != null && player.isPlaying();
-    }
-
-    public void start() {
-        if (!isOpen()) {
-            throw new IllegalStateException("Clip must be open");
-        }
-        
-        if (stream == null) {
-            throw new IllegalStateException("Need an AudioInputStream to play");
-        }
-
-        if (!isRunning()) {
-            /*
-             * This is ugly, but there is no way around it: The javax.sound API
-             * doesn't expect to throw an exception at this point for illegal
-             * MIDI sequences. Since we don't really construct the MIDI sequence
-             * from the original binary data, but only refer to its URL, the
-             * MediaPlayer can actually bail out at this point. We wrap the
-             * exception into a RuntimeException, to at least keep the API
-             * contract.
-             */
-            try {
-                String s = this.stream.getURL().toExternalForm();
-                
-                /*
-                 * TODO Workaround for 1107794: MediaPlayer doesn't handle
-                 * "file:" URLs. Get rid of this.
-                 */
-                if (s.startsWith("file:")) {
-                    s = s.substring(5);
-                }
-                
-                player.setDataSource(s);
-                player.setAudioStreamType(AudioManager.STREAM_MUSIC);
-                player.prepare();
-            } catch (IOException ex) {
-                throw new RuntimeException(ex.toString());
-            }
-            
-            player.start();
-        }
-    }
-
-    public void stop() {
-        if (!isOpen()) {
-            throw new IllegalStateException("Clip must be open");
-        }
-        
-        if (isRunning()) {
-            player.stop();
-        }
-    }
-
-    public void addLineListener(LineListener listener) {
-        throw new UnsupportedOperationException();
-    }
-
-    public void close() {
-        if (isOpen()) {
-            stop();
-            player = null;
-        }
-    }
-
-    public Control getControl(Type control) {
-        throw new IllegalArgumentException("No controls available");
-    }
-
-    public Control[] getControls() {
-        return new Control[0];
-    }
-
-    public javax.sound.sampled.Line.Info getLineInfo() {
-        return new Line.Info(this.getClass());
-    }
-
-    public boolean isControlSupported(Type control) {
-        return false;
-    }
-
-    public boolean isOpen() {
-        return player != null;
-    }
-
-    public void open() throws LineUnavailableException {
-        try {
-            player = new MediaPlayer();
-        } catch (Exception ex) {
-            throw new LineUnavailableException(ex.toString());
-        }
-    }
-
-    public void removeLineListener(LineListener listener) {
-        throw new UnsupportedOperationException();
-    }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/ControllerEventListener.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/ControllerEventListener.java
deleted file mode 100644
index 318139d..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/ControllerEventListener.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.EventListener;
-
-public interface ControllerEventListener extends EventListener {
-    void controlChange(ShortMessage event);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Instrument.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Instrument.java
deleted file mode 100644
index 397e53e..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Instrument.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-public abstract class Instrument extends SoundbankResource {
-    private Patch patch;
-
-    protected Instrument(Soundbank soundbank, Patch patch, String name, Class<?> dataClass) {
-        super(soundbank, name, dataClass);
-        this.patch = patch;
-    }
-
-    public Patch getPatch() {
-        return patch;
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/InvalidMidiDataException.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/InvalidMidiDataException.java
deleted file mode 100644
index bc1cb83..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/InvalidMidiDataException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-public class InvalidMidiDataException extends Exception {
-    private static final long serialVersionUID = 2780771756789932067L;
-
-    public InvalidMidiDataException() {
-        super();
-    }
-
-    public InvalidMidiDataException(String message) {
-        super(message);
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaEventListener.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaEventListener.java
deleted file mode 100644
index 0cf0d38..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaEventListener.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.EventListener;
-
-public interface MetaEventListener extends EventListener {
-    void meta(MetaMessage meta);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaMessage.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaMessage.java
deleted file mode 100644
index fe5d9cf..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaMessage.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class MetaMessage extends MidiMessage {
-    public static final int META = 255;
-    
-    private int dsp; //displacement from begin of array that 
-                     //return by method getData() from begin
-                     //of array that contain data
-    
-    public MetaMessage() {
-        super(new byte[] {-1, 0});
-    }
-
-    protected MetaMessage(byte[] data) {
-        super(data);
-        if (data == null) {
-            throw new NullPointerException();
-        }
-        if (super.length > 3) {
-            int n = 3;
-            while ((n <= super.length) && (super.data[n - 1] < 0)) {
-                n++;
-            }
-            dsp = n;
-        }
-    }
-
-    @Override
-    public Object clone() {
-        return new MetaMessage(this.getMessage());
-    }
-
-    public byte[] getData() {
-        if ((super.data != null) && (super.length > 3)) {
-            byte[] bt = new byte[super.length - dsp];
-            for (int i = dsp; i < super.length; i++) {
-                bt[i - dsp] = super.data[i];
-            }
-            return bt;
-        }
-        return new byte[0];
-    }
-
-    public int getType() {
-        if ((super.data != null) && (super.length >= 2)) {
-            return super.data[1] & 0xFF;
-        }
-        return 0;
-    }
-
-    public void setMessage(int type, byte[] data, int length) throws InvalidMidiDataException {
-        if (type < 0 || type >= 128) {
-            // sound.0A=Invalid meta event with type {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.0A", type)); //$NON-NLS-1$
-        }
-        if (length < 0 || (data != null && length > data.length)) {
-            // sound.03=length out of bounds: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.03", length)); //$NON-NLS-1$
-        }
-        try {
-            if (data == null) {
-                if (length != 0) {
-                    throw new NullPointerException();
-                }
-                super.setMessage(new byte[] { -1, (byte) type, 0 }, 3);
-            } else {
-                int div = 128;
-                int n = 1;
-                int ost;
-                int sm = 0;
-                while (length / div != 0) {
-                    n++;
-                    div *= 128;
-                }
-                int ln = n;
-                byte[] tdata = new byte[length + ln + 2];
-                div = 1;
-                ost = (length / div) % 128;
-                while (n != 0) {
-                    tdata[n - 1 + 2] = (byte) (ost + sm);
-                    n--;
-                    div *= 128;
-                    ost = (length / div) % 128;
-                    sm = 128;
-                }
-                tdata[0] = -1;
-                tdata[1] = (byte) type;
-                if (length > 0) {
-                    for (int i = 0; i < length; i++) {
-                        tdata[2 + ln + i] = data[i];
-                    }
-                }
-                super.setMessage(tdata, length + 2 + ln);
-                dsp = ln + 2;
-            }
-        } catch (InvalidMidiDataException e) {
-            throw e;
-        }
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiChannel.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiChannel.java
deleted file mode 100644
index e970641..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiChannel.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-public interface MidiChannel {
-    void allNotesOff();
-
-    void allSoundOff();
-
-    void controlChange(int controller, int value);
-
-    int getChannelPressure();
-
-    int getController(int controller);
-
-    boolean getMono();
-
-    boolean getMute();
-
-    boolean getOmni();
-
-    int getPitchBend();
-
-    int getPolyPressure(int noteNumber);
-
-    int getProgram();
-
-    boolean getSolo();
-
-    boolean localControl(boolean on);
-
-    void noteOff(int noteNumber);
-
-    void noteOff(int noteNumber, int velocity);
-
-    void noteOn(int noteNumber, int velocity);
-
-    void programChange(int program);
-
-    void programChange(int bank, int program);
-
-    void resetAllControllers();
-
-    void setChannelPressure(int pressure);
-
-    void setMono(boolean on);
-
-    void setMute(boolean mute);
-
-    void setOmni(boolean on);
-
-    void setPitchBend(int bend);
-
-    void setPolyPressure(int noteNumber, int pressure);
-
-    void setSolo(boolean soloState);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiDevice.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiDevice.java
deleted file mode 100644
index 9eb5169..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiDevice.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.List;
-
-public interface MidiDevice {
-    class Info {
-        private String name;
-
-        private String vendor;
-
-        private String description;
-
-        private String version;
-
-        protected Info(String name, String vendor, String description, String version) {
-            this.name = name;
-            this.vendor = vendor;
-            this.description = description;
-            this.version = version;
-        }
-
-        /*
-         * returns true when objects are the same
-         * 
-         * @see java.lang.Object#equals(java.lang.Object)
-         */
-        @Override
-        public final boolean equals(Object obj) {
-            return this == obj;
-        }
-
-        public final String getDescription() {
-            return description;
-        }
-
-        public final String getName() {
-            return name;
-        }
-
-        public final String getVendor() {
-            return vendor;
-        }
-
-        public final String getVersion() {
-            return version;
-        }
-
-        @Override
-        public final int hashCode() {
-            final int PRIME = 31;
-            int result = super.hashCode();
-            result = PRIME * result + ((description == null) ? 0 : description.hashCode());
-            result = PRIME * result + ((name == null) ? 0 : name.hashCode());
-            result = PRIME * result + ((vendor == null) ? 0 : vendor.hashCode());
-            result = PRIME * result + ((version == null) ? 0 : version.hashCode());
-            return result;
-        }
-
-        @Override
-        public final String toString() {
-            return name;
-        }
-    }
-
-    void close();
-
-    MidiDevice.Info getDeviceInfo();
-
-    int getMaxReceivers();
-
-    int getMaxTransmitters();
-
-    long getMicrosecondPosition();
-
-    Receiver getReceiver() throws MidiUnavailableException;
-
-    List<Receiver> getReceivers();
-
-    Transmitter getTransmitter() throws MidiUnavailableException;
-
-    List<Transmitter> getTransmitters();
-
-    boolean isOpen();
-
-    void open() throws MidiUnavailableException;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiEvent.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiEvent.java
deleted file mode 100644
index 145529b..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiEvent.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-public class MidiEvent {
-    private MidiMessage message;
-    
-    private long tick;
-    
-    public MidiEvent(MidiMessage message, long tick) {
-        this.message = message;
-        this.tick = tick;
-    }
-
-    public MidiMessage getMessage() {
-        return message;
-    }
-
-    public long getTick() {
-        return tick;
-    }
-
-    public void setTick(long tick) {
-        this.tick = tick;
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiFileFormat.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiFileFormat.java
deleted file mode 100644
index e4e9498..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiFileFormat.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-public class MidiFileFormat {
-    public static final int UNKNOWN_LENGTH = -1;
-
-    protected int byteLength;
-
-    protected float divisionType;
-
-    protected long microsecondLength;
-
-    protected int resolution;
-
-    protected int type;
-    
-    private HashMap<String, Object> properties;
-
-    public MidiFileFormat(int type, float divisionType, int resolution, int bytes,
-            long microseconds) {
-        this.type = type;
-        this.divisionType = divisionType;
-        this.resolution = resolution;
-        this.byteLength = bytes;
-        this.microsecondLength = microseconds;
-        this.properties = new HashMap<String, Object>();
-    }
-
-    public MidiFileFormat(int type, float divisionType, int resolution, int bytes,
-            long microseconds, Map<String, Object> properties) {
-        this.type = type;
-        this.divisionType = divisionType;
-        this.resolution = resolution;
-        this.byteLength = bytes;
-        this.microsecondLength = microseconds;
-        
-        this.properties = new HashMap<String, Object>();
-        this.properties.putAll(properties);
-    }
-
-    public int getByteLength() {
-        return byteLength;
-    }
-
-    public float getDivisionType() {
-        return divisionType;
-    }
-
-    public long getMicrosecondLength() {
-        return microsecondLength;
-    }
-
-    public Object getProperty(String key) {
-        return properties.get(key);
-    }
-
-    public int getResolution() {
-        return resolution;
-    }
-
-    public int getType() {
-        return type;
-    }
-
-    public Map<String, Object> properties() {
-        return Collections.unmodifiableMap(properties);
-        
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiMessage.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiMessage.java
deleted file mode 100644
index 1629ee1..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiMessage.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public abstract class MidiMessage implements Cloneable {
-
-    protected byte[] data;
-
-    protected int length;
-
-    protected MidiMessage(byte[] data) {
-        if (data == null) {
-            length = 0;
-        } else {
-            length = data.length;
-            this.data = data;
-        }
-    }
-
-    @Override
-    public abstract Object clone();
-
-    public int getLength() {
-        return length;
-    }
-
-    public byte[] getMessage() {
-        if (data == null) {
-            throw new NullPointerException();
-        }
-        return data.clone();
-    }
-
-    public int getStatus() {
-        if ((data == null) || (length == 0)) {
-            return 0;
-        }
-        return data[0] & 0xFF;
-    }
-
-    protected void setMessage(byte[] data, int length) throws InvalidMidiDataException {
-        if ((length < 0) || (length > data.length)) {
-            // sound.03=length out of bounds: {0}
-            throw new IndexOutOfBoundsException(Messages.getString("sound.03", length)); //$NON-NLS-1$
-        }
-
-        this.data = new byte[length];
-        if (length != 0) {
-            for (int i = 0; i < length; i++) {
-                this.data[i] = data[i];
-            }
-        }
-        this.length = length;
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiSystem.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiSystem.java
deleted file mode 100644
index eede0a9..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiSystem.java
+++ /dev/null
@@ -1,837 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URL;
-
-import javax.sound.midi.MidiDevice.Info;
-import javax.sound.midi.spi.MidiDeviceProvider;
-import javax.sound.midi.spi.MidiFileReader;
-import javax.sound.midi.spi.MidiFileWriter;
-import javax.sound.midi.spi.SoundbankReader;
-
-import org.apache.harmony.sound.utils.ProviderService;
-
-public class MidiSystem {
-    //path to javax.sound.midi.spi.MidiDeviceProvider file in the jar-file
-    private final static String midiDeviceProviderPath = 
-        "META-INF/services/javax.sound.midi.spi.MidiDeviceProvider";
-    
-    //path to javax.sound.midi.spi.MidiFileReader file in the jar-file
-    private final static String midiFileReaderPath =
-        "META-INF/services/javax.sound.midi.spi.MidiFileReader";
-    
-    //path to javax.sound.midi.spi.MidiFileWriter file in the jar-file
-    private final static String midiFileWriterPath =
-        "META-INF/services/javax.sound.midi.spi.MidiFileWriter";
-    
-    //path to javax.sound.midi.spi.SoundbankReader file in the jar-file
-    private final static String soundbankReaderPath =
-        "META-INF/services/javax.sound.midi.spi.SoundbankReader";
-    
-    //key to find default receiver in the sound.properties file
-    private final static String receiverName = "javax.sound.midi.Receiver";
-    
-    //key to find default sequencer in the sound.properties file
-    private final static String sequencerName = "javax.sound.midi.Sequencer";
-    
-    //key to find default synthesizer in the sound.properties file
-    private final static String synthesizerName = "javax.sound.midi.Synthesizer";
-    
-    //key to find default transmitter in the sound.properties file
-    private final static String transmitterName = "javax.sound.midi.Transmitter";
-    
-    public static MidiDevice getMidiDevice(MidiDevice.Info info)
-            throws MidiUnavailableException {
-        //FIXME
-        /*
-         * this method must to throw out MidiUnavailableException if requested device
-         * is not available
-         */
-        
-        /* 
-         * obtain the list of MidiDeviceProviders
-         */
-        List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
-        /*
-         * find device that describes by parameter info and return it
-         */
-        for (int i = 0; i < deviceProviders.size(); i++) {
-            MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
-            for (Info element : deviceInfo) {
-                if (element.equals(info)) {
-                    return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(info);
-                }
-            }
-        }
-        /*
-         * if we can't find device with requested info, we throw out IllegalArgumentException
-         */
-        throw new IllegalArgumentException("Requested device not installed: " + info.getName());
-    }
-
-    public static MidiDevice.Info[] getMidiDeviceInfo() {
-        /*
-         * obtain the list of MidiDeviceProviders
-         */
-        List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
-        //variable to save MidiDevice.Info
-        List<MidiDevice.Info> infos = new ArrayList<MidiDevice.Info>();
-        /*
-         * look through list of providers and save info of devices
-         */
-        for (int i = 0; i < deviceProviders.size(); i++) {
-            MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
-            for (Info element : deviceInfo) {
-                infos.add(element);
-            }
-        }
-        
-        MidiDevice.Info[] temp = new MidiDevice.Info[infos.size()];
-        return infos.toArray(temp);
-    }
-
-    public static MidiFileFormat getMidiFileFormat(File file) throws InvalidMidiDataException,
-            IOException {
-        /*
-         * obtain the list of MidiFileReaderProviders
-         */
-        List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
-        if (fileReaderProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no MidiFileReaderProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((MidiFileReader) fileReaderProviders.get(0)).getMidiFileFormat(file);
-    }
-
-    public static MidiFileFormat getMidiFileFormat(InputStream stream) throws InvalidMidiDataException, 
-            IOException {
-        /*
-         * obtain the list of MidiFileReaderProviders
-         */
-        List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
-        if (fileReaderProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no MidiFileReaderProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((MidiFileReader) fileReaderProviders.get(0)).getMidiFileFormat(stream);
-    }
-
-    public static MidiFileFormat getMidiFileFormat(URL url) throws InvalidMidiDataException,
-            IOException {
-        /*
-         * obtain the list of MidiFileReaderProviders
-         */
-        List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
-        if (fileReaderProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no MidiFileReaderProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((MidiFileReader) fileReaderProviders.get(0)).getMidiFileFormat(url);
-    }
-
-    public static int[] getMidiFileTypes() {
-        /*
-         * obtain the list of MidiFileWriterProviders
-         */
-        List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
-        if (fileWriterProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no MidiFileWriterProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((MidiFileWriter) fileWriterProviders.get(0)).getMidiFileTypes();
-    }
-
-    public static int[] getMidiFileTypes(Sequence sequence) {
-        /*
-         * obtain the list of MidiFileWriterProviders
-         */
-        List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
-        if (fileWriterProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no MidiFileWriterProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((MidiFileWriter) fileWriterProviders.get(0)).getMidiFileTypes(sequence);
-    }
-
-    public static Receiver getReceiver() throws MidiUnavailableException {
-        /*
-         * description of the default device for javax.sound.midi.Receiver
-         */
-        List<String> defaultDevice = ProviderService.getDefaultDeviceDescription(receiverName);
-        /*
-         * obtain the list of MidiDeviceProviders
-         */
-        List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
-        String provName;
-        int deviceNum = -1;
-        /*
-         * defaultDevice.get(0) --> provider
-         * defaultDevice.get(1) --> name
-         */      
-        if (defaultDevice.size() != 0) {
-            /*
-             * obtain the provider number in the list of deviceProviders that is provider for default device
-             */
-            for (int i = 0; i < deviceProviders.size(); i++) {
-                provName = deviceProviders.get(i).toString();
-                if (provName.substring(0, provName.indexOf("@")).equals(defaultDevice.get(0))) {
-                    deviceNum = i;
-                    break;
-                }
-            }
-            /*
-             * the first case: find the same provider and name that describes by default device
-             */
-            if (deviceNum != -1) {
-                MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDeviceInfo();
-                for (Info element : deviceInfo) {
-                    if (element.getName().equals(defaultDevice.get(1))) {
-                        try {
-                            return ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element).getReceiver();
-                        } catch (MidiUnavailableException e) {}
-                    }
-                }
-            for (Info element : deviceInfo) {
-                    try {
-                        return ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element).getReceiver();
-                    } catch (MidiUnavailableException e) {}
-                }
-            }
-            /*
-             * if we don't find again, find any receivers describe by name
-             */
-            for (int i = 0; i < deviceProviders.size(); i++) {
-                MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
-                for (Info element : deviceInfo) {
-                    if (element.getName().equals(defaultDevice.get(1))) {
-                        try {
-                            return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element).getReceiver();
-                        } catch (MidiUnavailableException e) {}
-                    }
-                }
-            }
-        }
-        /*
-         * in the last case we look throw all providers and find any receiver
-         */
-        for (int i = 0; i < deviceProviders.size(); i++) {
-            MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
-            for (Info element : deviceInfo) {
-                try {
-                    return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element).getReceiver();
-                } catch (MidiUnavailableException e) {}
-            }
-        }
-        /*
-         * if we don't find anyway, we throw out MidiUnavailableException
-         */
-        throw new MidiUnavailableException("There are no Recivers installed on your system!");
-    }
-
-    public static Sequence getSequence(File file) throws InvalidMidiDataException, IOException {
-        /*
-         * obtain the list of MidiFileReaderProviders
-         */
-        List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
-        // BEGIN android-added
-        try {
-            ((List)fileReaderProviders).add((Object)Class.forName("com.android.internal.sound.midi.AndroidMidiFileReader").newInstance());
-        } catch (Exception ex) {
-            // Ignore
-        }
-        // END android-added
-        if (fileReaderProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no MidiFileReaderProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((MidiFileReader) fileReaderProviders.get(0)).getSequence(file);
-    }
-
-    public static Sequence getSequence(InputStream stream) throws InvalidMidiDataException,
-            IOException {
-        /*
-         * obtain the list of MidiFileReaderProviders
-         */
-        List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
-        // BEGIN android-added
-        try {
-            ((List)fileReaderProviders).add(Class.forName("com.android.internal.sound.midi.AndroidMidiFileReader").newInstance());
-        } catch (Exception ex) {
-            // Ignore
-        }
-        // END android-added
-        if (fileReaderProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no MidiFileReaderProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((MidiFileReader) fileReaderProviders.get(0)).getSequence(stream);
-    }
-
-    public static Sequence getSequence(URL url) throws InvalidMidiDataException, IOException {
-        /*
-         * obtain the list of MidiFileReaderProviders
-         */
-        List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
-        // BEGIN android-added
-        try {
-            ((List)fileReaderProviders).add(Class.forName("com.android.internal.sound.midi.AndroidMidiFileReader").newInstance());
-        } catch (Exception ex) {
-            // Ignore
-        }
-        // END android-added
-        if (fileReaderProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no MidiFileReaderProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((MidiFileReader) fileReaderProviders.get(0)).getSequence(url);
-    }
-
-    public static Sequencer getSequencer() throws MidiUnavailableException {
-        /*
-         * this method is equals to method MidiSystem.getSequencer(true)
-         */
-        return getSequencer(true);
-    }
-
-    public static Sequencer getSequencer(boolean connected) throws MidiUnavailableException {
-        /*
-         * description of the default device for javax.sound.midi.Sequencer
-         */
-        List<String> defaultDevice = ProviderService.getDefaultDeviceDescription(sequencerName);
-        /*
-         * obtain the list of MidiDeviceProviders
-         */
-        List<?>  deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
-        
-        Sequencer sequencer;
-        Transmitter seqTrans;
-        Synthesizer synth;
-        Receiver recv;
-        String provName;
-        int deviceNum = -1;
-        /*
-         * defaultDevice.get(0) --> provider
-         * defaultDevice.get(1) --> name
-         */      
-        if (defaultDevice.size() != 0) {
-            /*
-             * obtain the provider number in the list of deviceProviders that is provider for default device
-             */
-            for (int i = 0; i < deviceProviders.size(); i++) {
-                provName = deviceProviders.get(i).toString();
-                if (provName.substring(0, provName.indexOf("@")).equals(defaultDevice.get(0))) {
-                    deviceNum = i;
-                    break;
-                }
-            }
-            /*
-             * the first case: find the same provider and name that describes by default device
-             */
-            if (deviceNum != -1) {
-                MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDeviceInfo();
-                for (Info element : deviceInfo) {
-                    if (element.getName().equals(defaultDevice.get(1))) {
-                        if (((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element) instanceof Sequencer) {
-                            if (connected) {
-                                sequencer = (Sequencer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
-                                seqTrans = sequencer.getTransmitter();
-                                try {
-                                    synth = MidiSystem.getSynthesizer();
-                                    recv = synth.getReceiver();                                    
-                                } catch (MidiUnavailableException e) {
-                                    /*
-                                     * if we haven't Synthesizer in the system, we use default receiver
-                                     */
-                                    recv = MidiSystem.getReceiver();
-                                }
-                                seqTrans.setReceiver(recv);
-                                return sequencer;
-                            }
-                            return (Sequencer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
-                        }
-                    }
-                }
-                for (Info element : deviceInfo) {
-                    if (((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element) instanceof Sequencer) {
-                        if (connected) {
-                            sequencer = (Sequencer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
-                            seqTrans = sequencer.getTransmitter();
-                            try {
-                                synth = MidiSystem.getSynthesizer();
-                                recv = synth.getReceiver();                                    
-                            } catch (MidiUnavailableException e) {
-                                /*
-                                 * if we haven't Synthesizer in the system, we use default receiver
-                                 */
-                                recv = MidiSystem.getReceiver();
-                            }
-                            seqTrans.setReceiver(recv);
-                            return sequencer;
-                        }
-                        return (Sequencer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
-                    }
-                }
-            }
-            /*
-             * if we don't find again, find any receivers describe by name
-             */
-            for (int i = 0; i < deviceProviders.size(); i++) {
-                MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
-                for (Info element : deviceInfo) {
-                    if (element.getName().equals(defaultDevice.get(1))) {
-                        if (((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element) instanceof Sequencer) {
-                            if (connected) {
-                                sequencer = (Sequencer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
-                                seqTrans = sequencer.getTransmitter();
-                                try {
-                                    synth = MidiSystem.getSynthesizer();
-                                    recv = synth.getReceiver();                                    
-                                } catch (MidiUnavailableException e) {
-                                    /*
-                                     * if we haven't Synthesizer in the system, we use default receiver
-                                     */
-                                    recv = MidiSystem.getReceiver();
-                                }
-                                seqTrans.setReceiver(recv);
-                                return sequencer;
-                            }
-                            return (Sequencer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
-                        }
-                    }
-                }
-            }
-        }
-        /*
-         * in the last case we look throw all providers and find any receiver
-         */
-        for (int i = 0; i < deviceProviders.size(); i++) {
-            MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
-            for (Info element : deviceInfo) {
-                if (((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element) instanceof Sequencer) {
-                    if (connected) {
-                        sequencer = (Sequencer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
-                        seqTrans = sequencer.getTransmitter();
-                        try {
-                            synth = MidiSystem.getSynthesizer();
-                            recv = synth.getReceiver();                                    
-                        } catch (MidiUnavailableException e) {
-                            /*
-                             * if we haven't Synthesizer in the system, we use default receiver
-                             */
-                            recv = MidiSystem.getReceiver();
-                        }
-                        seqTrans.setReceiver(recv);
-                        return sequencer;
-                    }
-                    return (Sequencer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
-                }
-            }
-        }
-        // BEGIN android-added
-        try {
-            return (Sequencer)(Class.forName("com.android.internal.sound.midi.AndroidSequencer").newInstance());
-        } catch (Exception ex) {
-            // Ignore
-        }
-        // END android-added
-        /*
-         * if we don't find anyway, we throw out MidiUnavailableException
-         */
-        throw new MidiUnavailableException("There are no Synthesizers installed on your system!");
-    }
-
-    public static Soundbank getSoundbank(File file) throws InvalidMidiDataException,
-            IOException {
-        /*
-         * obtain the list of SoundbankReaderProviders
-         */
-        List<?> soundbankReaderProviders = ProviderService.getProviders(soundbankReaderPath);
-        if (soundbankReaderProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no SoundbankReaderProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((SoundbankReader) soundbankReaderProviders.get(0)).getSoundbank(file);
-    }
-
-    public static Soundbank getSoundbank(InputStream stream) throws InvalidMidiDataException, IOException {
-        /*
-         * obtain the list of SoundbankReaderProviders
-         */
-        List<?> soundbankReaderProviders = ProviderService.getProviders(soundbankReaderPath);
-        if (soundbankReaderProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no SoundbankReaderProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((SoundbankReader) soundbankReaderProviders.get(0)).getSoundbank(stream);
-    }
-
-    public static Soundbank getSoundbank(URL url) throws InvalidMidiDataException, IOException {
-        /*
-         * obtain the list of SoundbankReaderProviders
-         */
-        List<?> soundbankReaderProviders = ProviderService.getProviders(soundbankReaderPath);
-        if (soundbankReaderProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no SoundbankReaderProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((SoundbankReader) soundbankReaderProviders.get(0)).getSoundbank(url);
-    }
-
-    public static Synthesizer getSynthesizer() throws MidiUnavailableException {
-        /*
-         * description of the default device for javax.sound.midi.Synthesizer
-         */
-        List<String> defaultDevice = ProviderService.getDefaultDeviceDescription(synthesizerName);
-        /*
-         * obtain the list of MidiDeviceProviders
-         */
-        List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
-        String provName;
-        int deviceNum = -1;
-        
-        /*
-         * defaultDevice.get(0) --> provider
-         * defaultDevice.get(1) --> name
-         */      
-        if (defaultDevice.size() != 0) {
-            /*
-             * obtain the provider number in the list of deviceProviders that is provider for default device
-             */
-            for (int i = 0; i < deviceProviders.size(); i++) {
-                provName = deviceProviders.get(i).toString();
-                if (provName.substring(0, provName.indexOf("@")).equals(defaultDevice.get(0))) {
-                    deviceNum = i;
-                    break;
-                }
-            }
-            /*
-             * the first case: find the same provider and name that describes by default device
-             */
-            if (deviceNum != -1) {
-                MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDeviceInfo();
-                for (Info element : deviceInfo) {
-                    if (element.getName().equals(defaultDevice.get(1))) {
-                        if (((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element) instanceof Synthesizer) {
-                            return (Synthesizer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
-                        }
-                    }
-                }
-                for (Info element : deviceInfo) {
-                    if (((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element) instanceof Synthesizer) {
-                        return (Synthesizer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
-                    }
-                }
-            }
-            /*
-             * if we don't find again, find any receivers describe by name
-             */
-            for (int i = 0; i < deviceProviders.size(); i++) {
-                MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
-                for (Info element : deviceInfo) {
-                    if (element.getName().equals(defaultDevice.get(1))) {
-                        if (((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element) instanceof Synthesizer) {
-                            return (Synthesizer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
-                        }
-                    }
-                }
-            }
-        }
-        /*
-         * in the last case we look throw all providers and find any receiver
-         */
-        for (int i = 0; i < deviceProviders.size(); i++) {
-            MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
-            for (Info element : deviceInfo) {
-                if (((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element) instanceof Synthesizer) {
-                    return (Synthesizer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
-                }
-            }
-        }
-        /*
-         * if we don't find anyway, we throw out MidiUnavailableException
-         */
-        throw new MidiUnavailableException("There are no Synthesizers installed on your system!");
-    }
-
-    public static Transmitter getTransmitter() throws MidiUnavailableException {
-        /*
-         * description of the default device for javax.sound.midi.Transmitter
-         */
-        List<String> defaultDevice = ProviderService.getDefaultDeviceDescription(transmitterName);
-        /*
-         * obtain the list of MidiDeviceProviders
-         */
-        List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
-        String provName;
-        int deviceNum = -1;
-        /*
-         * defaultDevice.get(0) --> provider
-         * defaultDevice.get(1) --> name
-         */      
-        if (defaultDevice.size() != 0) {
-            /*
-             * obtain the provider number in the list of deviceProviders that is provider for default device
-             */
-            for (int i = 0; i < deviceProviders.size(); i++) {
-                provName = deviceProviders.get(i).toString();
-                if (provName.substring(0, provName.indexOf("@")).equals(defaultDevice.get(0))) {
-                    deviceNum = i;
-                    break;
-                }
-            }
-            /*
-             * the first case: find the same provider and name that describes by default device
-             */
-            if (deviceNum != -1) {
-                MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDeviceInfo();
-                for (Info element : deviceInfo) {
-                    if (element.getName().equals(defaultDevice.get(1))) {
-                        try {
-                            return ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element).getTransmitter();
-                        } catch (MidiUnavailableException e) {}
-                    }
-                }
-                for (Info element : deviceInfo) {
-                    try {
-                        return ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element).getTransmitter();
-                    } catch (MidiUnavailableException e) {}
-                }
-            }
-            /*
-             * if we don't find again, find any receivers describe by name
-             */
-            for (int i = 0; i < deviceProviders.size(); i++) {
-                MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
-                for (Info element : deviceInfo) {
-                    if (element.getName().equals(defaultDevice.get(1))) {
-                        try {
-                            return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element).getTransmitter();
-                        } catch (MidiUnavailableException e) {}
-                    }
-                }
-            }
-        }
-        /*
-         * in the last case we look throw all providers and find any receiver
-         */
-        for (int i = 0; i < deviceProviders.size(); i++) {
-            MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
-            for (Info element : deviceInfo) {
-                try {
-                    return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element).getTransmitter();
-                } catch (MidiUnavailableException e) {}
-            }
-        }
-        /*
-         * if we don't find anyway, we throw out MidiUnavailableException
-         */
-        throw new MidiUnavailableException("There are no Transmitters installed on your system!");
-    }
-
-    public static boolean isFileTypeSupported(int fileType) {
-        /*
-         * obtain the list of MidiFileWriterProviders;
-         * if we already obtain the list of providers, we don't obtain it again
-         */
-        List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
-        if (fileWriterProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no MidiFileWriterProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((MidiFileWriter) fileWriterProviders.get(0)).isFileTypeSupported(fileType);
-    }
-
-    public static boolean isFileTypeSupported(int fileType, Sequence sequence) {
-        /*
-         * obtain the list of MidiFileWriterProviders
-         */
-        List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
-        if (fileWriterProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no MidiFileWriterProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((MidiFileWriter) fileWriterProviders.get(0)).isFileTypeSupported(fileType, sequence);
-    }
-
-    public static int write(Sequence in, int type, File out) throws IOException {
-        /*
-         * obtain the list of MidiFileWriterProviders
-         */
-        List<?>  fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
-        if (fileWriterProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no MidiFileWriterProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((MidiFileWriter) fileWriterProviders.get(0)).write(in, type, out);
-    }
-
-    public static int write(Sequence in, int fileType, OutputStream out) throws IOException {
-        /*
-         * obtain the list of MidiFileWriterProviders
-         */
-        List<?>  fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
-        if (fileWriterProviders.size() == 0) {
-            //FIXME
-            /*
-             * I don't understand what type of exception we should throw out if we haven't
-             * appropriate providers...
-             * Maybe here is should be MidiUnavailableException
-             */
-            throw new Error("There is no MidiFileWriterProviders on your system!!!");
-        }
-        /*
-         * It's not determine what provider for this service I should to use, and so
-         * I use the first one
-         */
-        return ((MidiFileWriter) fileWriterProviders.get(0)).write(in, fileType, out);
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Patch.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Patch.java
deleted file mode 100644
index fc1d280..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Patch.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-public class Patch {
-    private int bank;
-
-    private int program;
-
-    public Patch(int bank, int program) {
-        this.bank = bank;
-        this.program = program;
-    }
-
-    public int getBank() {
-        return bank;
-    }
-
-    public int getProgram() {
-        return program;
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Receiver.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Receiver.java
deleted file mode 100644
index 014c05f..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Receiver.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-public interface Receiver {
-    void close();
-
-    void send(MidiMessage message, long timeStamp);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Sequence.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Sequence.java
deleted file mode 100644
index 0a12834..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Sequence.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.Vector;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class Sequence {
-    public static final float PPQ = 0.0f;
-
-    public static final float SMPTE_24 = 24.0f;
-
-    public static final float SMPTE_25 = 25.0f;
-
-    public static final float SMPTE_30 = 30.0f;
-
-    public static final float SMPTE_30DROP = 29.969999313354492f;
-    
-    protected float divisionType;
-
-    protected int resolution;
-
-    protected Vector<Track> tracks;
-    
-    private Vector<Patch> patches;
-
-    public Sequence(float divisionType, int resolution) throws InvalidMidiDataException {
-        if (divisionType != Sequence.PPQ &&
-                divisionType != Sequence.SMPTE_24 &&
-                divisionType != Sequence.SMPTE_25 &&
-                divisionType != Sequence.SMPTE_30 &&
-                divisionType != Sequence.SMPTE_30DROP ) {
-            // sound.0B=Unsupported division type: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.0B", divisionType));       //$NON-NLS-1$
-        }
-        this.divisionType = divisionType;
-        this.resolution = resolution;
-        this.tracks = new Vector<Track>();
-        this.patches = new Vector<Patch>();
-        
-    }
-
-    public Sequence(float divisionType, int resolution, int numTracks)
-            throws InvalidMidiDataException {
-        if (divisionType != Sequence.PPQ &&
-                divisionType != Sequence.SMPTE_24 &&
-                divisionType != Sequence.SMPTE_25 &&
-                divisionType != Sequence.SMPTE_30 &&
-                divisionType != Sequence.SMPTE_30DROP ) {
-            // sound.0B=Unsupported division type: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.0B", divisionType));       //$NON-NLS-1$
-        }
-        this.divisionType = divisionType;
-        this.resolution = resolution;
-        this.patches = new Vector<Patch>();
-        this.tracks = new Vector<Track>();
-        if (numTracks > 0) {
-            for (int i = 0; i < numTracks; i++) {
-                tracks.add(new Track());
-            }
-        }
-    }
-
-    public Track createTrack() {
-        /*
-         * new Tracks accrue to the end of vector
-         */
-        Track tr = new Track();
-        tracks.add(tr);
-        return tr;
-    }
-
-    public boolean deleteTrack(Track track) {
-        return tracks.remove(track);
-    }
-
-    public float getDivisionType() {
-        return divisionType;
-    }
-
-    public long getMicrosecondLength() {
-        float divisionType;
-        if (this.divisionType == 0.0f) {
-            divisionType = 2;
-        } else {
-            divisionType = this.divisionType;
-        }
-        return (long) (1000000.0 * getTickLength() / 
-                (divisionType * this.resolution * 1.0f));
-    }
-
-    public Patch[] getPatchList() {
-        //FIXME
-        /*
-         * I don't understand how to works this method, and so
-         * I simply return an empty array. 'patches' initializes
-         * in the constructor as empty vector 
-         */
-        Patch[] patch = new Patch[patches.size()];
-        patches.toArray(patch);
-        return patch;
-    }
-
-    public int getResolution() {
-        return resolution;
-    }
-
-    public long getTickLength() {
-        /*
-         * this method return the biggest value of tick of 
-         * all tracks contain in the Sequence
-         */
-        long maxTick = 0;
-        for (int i = 0; i < tracks.size(); i++) {
-            if (maxTick < tracks.get(i).ticks()) {
-                maxTick = tracks.get(i).ticks();
-            }
-        }
-        return maxTick;
-    }
-
-    public Track[] getTracks() {
-        Track[] track = new Track[tracks.size()];
-        tracks.toArray(track);
-        return track;
-    }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Sequencer.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Sequencer.java
deleted file mode 100644
index 4f0d8f8..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Sequencer.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-public interface Sequencer extends MidiDevice {
-    int LOOP_CONTINUOUSLY = -1;
-
-    class SyncMode {
-        public static final SyncMode INTERNAL_CLOCK = new SyncMode("INTERNAL_CLOCK"); //$NON-NLS-1$
-
-        public static final SyncMode MIDI_SYNC = new SyncMode("MIDI_SYNC"); //$NON-NLS-1$
-
-        public static final SyncMode MIDI_TIME_CODE = new SyncMode("MIDI_TIME_CODE"); //$NON-NLS-1$
-
-        public static final SyncMode NO_SYNC = new SyncMode("NO_SYNC"); //$NON-NLS-1$
-
-        private String name;
-
-        protected SyncMode(String name) {
-            this.name = name;
-        }
-
-        @Override
-        public final boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (!super.equals(obj)) {
-                return false;
-            }
-            if (getClass() != obj.getClass()) {
-                return false;
-            }
-            final SyncMode other = (SyncMode) obj;
-            if (name == null) {
-                if (other.name != null) {
-                    return false;
-                }
-            } else if (!name.equals(other.name)) {
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public final int hashCode() {
-            final int PRIME = 31;
-            int result = super.hashCode();
-            result = PRIME * result + ((name == null) ? 0 : name.hashCode());
-            return result;
-        }
-
-        @Override
-        public final String toString() {
-            return name;
-        }
-    }
-
-    int[] addControllerEventListener(ControllerEventListener listener, int[] controllers);
-
-    boolean addMetaEventListener(MetaEventListener listener);
-
-    int getLoopCount();
-
-    long getLoopEndPoint();
-
-    long getLoopStartPoint();
-
-    Sequencer.SyncMode getMasterSyncMode();
-
-    Sequencer.SyncMode[] getMasterSyncModes();
-
-    long getMicrosecondLength();
-
-    long getMicrosecondPosition();
-
-    Sequence getSequence();
-
-    Sequencer.SyncMode getSlaveSyncMode();
-
-    Sequencer.SyncMode[] getSlaveSyncModes();
-
-    float getTempoFactor();
-
-    float getTempoInBPM();
-
-    float getTempoInMPQ();
-
-    long getTickLength();
-
-    long getTickPosition();
-
-    boolean getTrackMute(int track);
-
-    boolean getTrackSolo(int track);
-
-    boolean isRecording();
-
-    boolean isRunning();
-
-    void recordDisable(Track track);
-
-    void recordEnable(Track track, int channel);
-
-    int[] removeControllerEventListener(ControllerEventListener listener, int[] controllers);
-
-    void removeMetaEventListener(MetaEventListener listener);
-
-    void setLoopCount(int count);
-
-    void setLoopEndPoint(long tick);
-
-    void setLoopStartPoint(long tick);
-
-    void setMasterSyncMode(Sequencer.SyncMode sync);
-
-    void setMicrosecondPosition(long microseconds);
-
-    void setSequence(InputStream stream) throws IOException, InvalidMidiDataException;
-
-    void setSequence(Sequence sequence) throws InvalidMidiDataException;
-
-    void setSlaveSyncMode(Sequencer.SyncMode sync);
-
-    void setTempoFactor(float factor);
-
-    void setTempoInBPM(float bpm);
-
-    void setTempoInMPQ(float mpq);
-
-    void setTickPosition(long tick);
-
-    void setTrackMute(int track, boolean mute);
-
-    void setTrackSolo(int track, boolean solo);
-
-    void start();
-
-    void startRecording();
-
-    void stop();
-
-    void stopRecording();
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/ShortMessage.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/ShortMessage.java
deleted file mode 100644
index e75b784..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/ShortMessage.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class ShortMessage extends MidiMessage {
-
-    public static final int ACTIVE_SENSING = 254;
-
-    public static final int CHANNEL_PRESSURE = 208;
-
-    public static final int CONTINUE = 251;
-
-    public static final int CONTROL_CHANGE = 176;
-
-    public static final int END_OF_EXCLUSIVE = 247;
-
-    public static final int MIDI_TIME_CODE = 241;
-
-    public static final int NOTE_OFF = 128;
-
-    public static final int NOTE_ON = 144;
-
-    public static final int PITCH_BEND = 224;
-
-    public static final int POLY_PRESSURE = 160;
-
-    public static final int PROGRAM_CHANGE = 192;
-
-    public static final int SONG_POSITION_POINTER = 242;
-
-    public static final int SONG_SELECT = 243;
-
-    public static final int START = 250;
-
-    public static final int STOP = 252;
-
-    public static final int SYSTEM_RESET = 255;
-
-    public static final int TIMING_CLOCK = 248;
-
-    public static final int TUNE_REQUEST = 246;
-
-    public ShortMessage() {
-        super(new byte[] {-112, 64, 127});
-    }
-
-    protected ShortMessage(byte[] data) {
-        super(data);
-    }
-
-    @Override
-    public Object clone() {
-        return new ShortMessage(this.getMessage());
-    }
-
-    public int getChannel() {
-        /*
-         * channel change from 0 up to 15
-         */
-        if ((data == null) || (data.length == 0)) {
-            return 0;
-        }
-        return data[0] & 0x0F;
-    }
-
-    public int getCommand() {
-       /*
-        * command should be divisible by 16 without rest 
-        */
-        if ((data == null) || (data.length == 0)) {
-            return 0;
-        }
-        return (data[0] & 0xFF) - getChannel();
-    }
-
-    public int getData1() {
-        if ((data == null) || (data.length == 0)) {
-            return 0;
-        } else if (data.length < 2) {
-            return 0;
-        } else {
-            return data[1] & 0xFF;
-        }
-    }
-
-    public int getData2() {
-        if ((data == null) || (data.length == 0)) {
-            return 0;
-        } else if (data.length < 3) {
-            return 0;
-        } else {
-            return data[2] & 0xFF;
-        }
-    }
-
-    protected final int getDataLength(int status)
-            throws InvalidMidiDataException {
-        // FIXME
-        /*
-         * I have some question about this method. I didn't understand how
-         * should to work this method, but some results I get by experimental
-         * method. From 0 up to 127, from 256 up to 383 and so on this method
-         * throw out exception, i.e. after 256 begin cycle with some small
-         * differences in the first lap, from 0 up to 255. From the second lap
-         * and so on this method, getDataLenght(int), throw out exception with
-         * value of status from 496 up to 511, from 752 up to 767 and so on,
-         * i.e. on the last 16 number of 256-lap. And now differences in the
-         * first lap. This method don't throw out exception with value of status
-         * from 240 up to 255. It has next behavior: 
-         * - value of status equals 240 -- throw out exception; 
-         * - 241 -- return 1; 
-         * - 242 -- return 2; 
-         * - 243 -- return 1; 
-         * - from 244 up to 245 -- throw out exception; 
-         * - from 246 up to 255 -- return 0;
-         */
-        if (status < 0) {
-            // sound.04=Invalid status byte: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
-        }
-        if (((status % 256) >= 0) && ((status % 256) <= 127)) {
-            // sound.04=Invalid status byte: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
-        }
-        if (((status / 256) == 0)
-                && ((status == 240) || (status == 244) || (status == 245))) {
-            // sound.04=Invalid status byte: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
-        }
-        if (((status / 256) != 0) && ((status % 256) >= 244)
-                && ((status % 256) <= 255)) {
-            // sound.04=Invalid status byte: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
-        }
-
-        if ((status / 256) == 0) {
-            if ((status == 241) || (status == 243)) {
-                return 1;
-            } else if (status == 242) {
-                return 2;
-            } else if ((status >= 246) && (status <= 255)) {
-                return 0;
-            }
-        }
-        if (((status % 256) >= 128) && ((status % 256) <= 191)) {
-            return 2;
-        } else if (((status % 256) >= 192) && ((status % 256) <= 223)) {
-            return 1;
-        } else {
-            return 2;
-        }
-    }
-
-    public void setMessage(int status) throws InvalidMidiDataException {
-        /*
-         * value of variable status is more or equals 246 and less or equals 255
-         */
-        if ((status < 246) || (status > 255)) {
-            // sound.04=Invalid status byte: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
-        }
-        super.setMessage(new byte[] {(byte) status}, 1);
-    }
-
-    public void setMessage(int status, int data1, int data2)
-            throws InvalidMidiDataException {
-        // FIXME
-        /*
-         * In the Sun's implementation variables data1 and data2 don't use; I
-         * don't find situation when this variables influence on result of
-         * functions getData1() and getData2(). But function getDataLength(int)
-         * return 0 when I modify status byte from 246 up to 255, and so I think
-         * it's true.
-         */
-        if ((status < 246) || (status > 255)) {
-            // sound.04=Invalid status byte: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.04", status)); //$NON-NLS-1$
-        }
-        super.setMessage(new byte[] {(byte) status}, 1);
-    }
-
-    public void setMessage(int command, int channel, int data1, int data2)
-            throws InvalidMidiDataException {
-        // FIXME
-        /*
-         * value of variable command is more or equals 128 and less or equals
-         * 239
-         */
-        if ((command < 128) || (command > 239)) {
-            /*
-             * when this exception throw out, the value of variable command
-             * should be the hexadecimal number
-             */
-            // sound.05=command out of range: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.05", command)); //$NON-NLS-1$
-        }
-        /*
-         * value of variable channel is more or equals 0 and less or equals 15
-         */
-        if ((channel < 0) || (channel > 15)) {
-            // sound.06=channel out of range: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.06", channel)); //$NON-NLS-1$
-        }
-        /*
-         * value of data1 and data2 is more or equals 0 and less or equals 127,
-         * but when command more or equals 192 and less or equals 223 the second
-         * data, data2, is unused, because getDataLength(int) return 1 in this
-         * case, and in other cases it return 2
-         */
-        if ((getDataLength(command) >= 1) && ((data1 < 0) || (data1 > 127))) {
-            // sound.07=data1 out of range: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.07", data1)); //$NON-NLS-1$
-        }
-        if ((getDataLength(command) == 2) && ((data2 < 0) || (data2 > 127))) {
-            // sound.08=data2 out of range: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.08", data2)); //$NON-NLS-1$
-        }
-
-        int tcom = command - (command % 16);
-        if (getDataLength(command) == 1) {
-            super.setMessage(new byte[] {(byte) (tcom + channel), (byte) data1}, 2);
-        } else {
-            super.setMessage(new byte[] {(byte) (tcom + channel), (byte) data1, 
-                    (byte) data2}, 3);
-        }
-    }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Soundbank.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Soundbank.java
deleted file mode 100644
index c2a7a85..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Soundbank.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-public interface Soundbank {
-    String getDescription();
-
-    Instrument getInstrument(Patch patch);
-
-    Instrument[] getInstruments();
-
-    String getName();
-
-    SoundbankResource[] getResources();
-
-    String getVendor();
-
-    String getVersion();
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/SoundbankResource.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/SoundbankResource.java
deleted file mode 100644
index d824d53..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/SoundbankResource.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-public abstract class SoundbankResource {
-    private Soundbank soundbank;
-    private String name;
-    private Class<?> dataClass;
-    
-    protected SoundbankResource(Soundbank soundbank, String name, Class<?> dataClass) {
-        super();
-        this.soundbank = soundbank;
-        this.name = name;
-        this.dataClass = dataClass;
-    }
-
-    public abstract Object getData();
-
-    public Class<?> getDataClass() {
-        return dataClass;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public Soundbank getSoundbank() {
-        return soundbank;
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Synthesizer.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Synthesizer.java
deleted file mode 100644
index b203a85..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Synthesizer.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-public interface Synthesizer extends MidiDevice {
-    Instrument[] getAvailableInstruments();
-
-    MidiChannel[] getChannels();
-
-    Soundbank getDefaultSoundbank();
-
-    long getLatency();
-
-    Instrument[] getLoadedInstruments();
-
-    int getMaxPolyphony();
-
-    VoiceStatus[] getVoiceStatus();
-
-    boolean isSoundbankSupported(Soundbank soundbank);
-
-    boolean loadAllInstruments(Soundbank soundbank);
-
-    boolean loadInstrument(Instrument instrument);
-
-    boolean loadInstruments(Soundbank soundbank, Patch[] patchList);
-
-    boolean remapInstrument(Instrument from, Instrument to);
-
-    void unloadAllInstruments(Soundbank soundbank);
-
-    void unloadInstrument(Instrument instrument);
-
-    void unloadInstruments(Soundbank soundbank, Patch[] patchList);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/SysexMessage.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/SysexMessage.java
deleted file mode 100644
index 8ba7b86..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/SysexMessage.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class SysexMessage extends MidiMessage {
-    public static final int SPECIAL_SYSTEM_EXCLUSIVE = 247;
-
-    public static final int SYSTEM_EXCLUSIVE = 240;
-
-    public SysexMessage() {
-        super(new byte[] {-16, -9});
-    }
-
-    protected SysexMessage(byte[] data) {
-        super(data);
-    }
-
-    @Override
-    public Object clone() {
-        return new SysexMessage(this.getMessage());
-    }
-
-    public byte[] getData() {
-        byte[] bt = new byte[super.length - 1];
-        for(int i = 1; i < super.length; i++) {
-            bt[i-1] = super.data[i];
-        }
-        return bt;
-    }
-
-    @Override
-    public void setMessage(byte[] data, int length) throws InvalidMidiDataException {
-        //FIXME
-        /*
-         * if this exception throw out, the value of wrong status byte
-         * should be the hexadecimal value
-         */
-        if(((data[0] & 0xFF) != SysexMessage.SPECIAL_SYSTEM_EXCLUSIVE) &&
-                ((data[0] & 0xFF) != SysexMessage.SYSTEM_EXCLUSIVE)) {
-            // sound.09=Invalid status byte for sysex message: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.09",  //$NON-NLS-1$
-                    data[0] & 0xFF));
-        }
-        super.setMessage(data, length);
-    }
-
-    public void setMessage(int status, byte[] data, int length) throws InvalidMidiDataException {
-        //FIXME
-        /*
-         * if this exception throw out, the value of wrong status byte
-         * should be the hexadecimal value
-         */
-        if((status != SysexMessage.SPECIAL_SYSTEM_EXCLUSIVE) &&
-                (status != SysexMessage.SYSTEM_EXCLUSIVE)) {
-            // sound.09=Invalid status byte for sysex message: {0}
-            throw new InvalidMidiDataException(Messages.getString("sound.09",  //$NON-NLS-1$
-                    status));
-        }
-        if((length < 0) || (length > data.length)) {
-            // sound.03=length out of bounds: {0}
-            throw new IndexOutOfBoundsException(Messages.getString("sound.03", length)); //$NON-NLS-1$
-        }
-        byte[] bt = new byte[length + 1];
-        bt[0] = (byte) status;
-        for(int i = 0; i < length; i++) {
-            bt[i+1] = data[i];
-        }
-        super.setMessage(bt, length + 1);
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Track.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Track.java
deleted file mode 100644
index 27dab92..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Track.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.ArrayList;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class Track {
-    private ArrayList<MidiEvent> events; //vector of events contain in the Track
-    
-    private MidiEvent badEvent; //variable to save event which I try to add
-                                //to empty Track; see description below
-    
-    private long tick; 
-    
-    Track() {
-        /*
-         * create an empty Track; new Track must contain only meta-event End of Track.
-         * MetaMessage with MetaMessage.data contains -1, 47 and 0 is meta-event
-         */
-        events = new ArrayList<MidiEvent>();
-        events.add(new MidiEvent(new MetaMessage(new byte[] {-1, 47, 0}), 0));
-    }
-    public boolean add(MidiEvent event) {
-        //FIXME
-        /*
-         * Some words about badEvent.
-         * When I write tests, I find following situation in the RI:
-         * if I want to add to empty Track new event that is not meta-event End of Track,
-         * I catch exception ArrayIndexOutOfBoundsException with meaning -1, and my
-         * event doesn't add to Track, but meta-event adds. If I try to add the same 
-         * event after it, method Track.add(MidiEvent) return 'false', and my event
-         * doesn't add again. So, I want to delete this event and use method 
-         * Track.remove(MidiEvent) for it, but it return 'false' too! And only after
-         * this "shamanism" I can add this event to Track normally. 
-         * And only for this situation I use variable badEvent. 
-         * 
-         * See test org.apache.harmony.sound.tests.javax.sound.midi.TrackTest 
-         * for more details
-         */
-        
-        /*
-         * if event equals null or badEvent, this method return 'false'
-         */
-        if (event == null || event == badEvent) {
-            return false;
-        }
-        /*
-         * If event equals meta-event End of Track and Track in this moment
-         * doesn't contain some events, i.e. Track.size() return 0, this 
-         * event accrue to Track; 
-         * if Track is not empty, but it doesn't contain meta-event, 
-         * this event accrue to the end of Track;
-         * in any case addition of this meta-event is successful, this method 
-         * return 'true' even if meta-event End of Track already contains in the Track
-         */
-        if (event.getMessage().getMessage()[0] == -1 &&
-                event.getMessage().getMessage()[1] == 47 &&
-                event.getMessage().getMessage()[2] == 0 ) {
-            if (events.size() == 0) {
-                return events.add(event);
-            }
-            byte[] bt = events.get(events.size() - 1).getMessage().getMessage();
-            if ((bt[0] != -1) && (bt[1] != 47) && (bt[2] != 0)) {
-                return events.add(event);
-            }         
-            return true;
-        }
-        /*
-         * after use method Track.add(MidiEvent) Track must contain meta-event
-         * End of Track; so, at first I add this event to Track if it doesn't 
-         * contain meta-event and parameter 'event' is not meta-event
-         */
-        if (events.size() == 0) {
-            events.add(new MidiEvent(new MetaMessage(new byte[] {-1, 47, 0}), 0));
-            badEvent = event;
-            // sounds.01=-1
-            throw new ArrayIndexOutOfBoundsException(Messages.getString("sound.01")); //$NON-NLS-1$
-        }
-        byte[] bt = events.get(events.size() - 1).getMessage().getMessage();
-        if ((bt[0] != -1) && (bt[1] != 47) && (bt[2] != 0)) {
-            events.add(new MidiEvent(new MetaMessage(new byte[] {-1, 47, 0}), 0));
-        }
-        
-        if (events.contains(event)) {
-            return false;
-        } 
-        
-        /*
-         * events in the Track must take up position in ascending ticks
-         */
-        if (events.size() == 1) {
-            events.add(0, event);
-        }
-        for (int i = 0; i < events.size() - 1; i++ ) {
-            if (events.get(i).getTick() <= event.getTick()) {
-                continue;
-            }
-            events.add(i, event);
-            break;
-        }
-        /*
-         * method Track.ticks() return the biggest value of tick of all events
-         * and save it even I remove event with the biggest values of tick
-         */
-        if (tick < event.getTick()) {
-            tick = event.getTick();
-        }
-        return true;           
-    }
-
-    public MidiEvent get(int index) throws ArrayIndexOutOfBoundsException {
-        if (index < 0 || index >= events.size()) {
-            // sound.02=Index: {0}, Size: {1}
-            throw new ArrayIndexOutOfBoundsException(Messages.getString("sound.02", index, events.size()));  //$NON-NLS-1$
-        }
-        return events.get(index);
-    }
-
-    public boolean remove(MidiEvent event) {
-        /*
-         * if I remove event that equals badEvent, I "delete" badEvent
-         */
-        if (event == badEvent) {
-            badEvent = null;
-            return false;
-        }
-        /*
-         * method Track.ticks() always return the biggest value that ever has been
-         * in the Track; so only when Track is empty Track.ticks() return 0 
-         */
-        if (events.remove(event)) {
-            if (events.size() == 0) {
-                tick = 0;
-            }
-            return true;
-        }
-        return false;
-    }
-
-    public int size() {
-        return events.size();
-    }
-
-    public long ticks() {
-        return tick;
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Transmitter.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Transmitter.java
deleted file mode 100644
index 1e89197..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Transmitter.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-public interface Transmitter {
-    void close();
-
-    Receiver getReceiver();
-
-    void setReceiver(Receiver receiver);
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/VoiceStatus.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/VoiceStatus.java
deleted file mode 100644
index 370f48e..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/VoiceStatus.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi;
-
-public class VoiceStatus {
-    public boolean active;
-
-    public int bank;
-
-    public int channel;
-
-    public int note;
-
-    public int program;
-
-    public int volume;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiDeviceProvider.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiDeviceProvider.java
deleted file mode 100644
index 6112ec7..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiDeviceProvider.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi.spi;
-
-import javax.sound.midi.MidiDevice;
-import javax.sound.midi.MidiDevice.Info;
-
-public abstract class MidiDeviceProvider {
-
-    public abstract MidiDevice getDevice(MidiDevice.Info info);
-
-    public abstract MidiDevice.Info[] getDeviceInfo();
-
-    public boolean isDeviceSupported(MidiDevice.Info info) {
-        MidiDevice.Info[] devices = getDeviceInfo();
-        for (Info element : devices) {
-            if (info.equals(element)) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiFileReader.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiFileReader.java
deleted file mode 100644
index 0d61181..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiFileReader.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi.spi;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.MidiFileFormat;
-import javax.sound.midi.Sequence;
-
-public abstract class MidiFileReader {
-
-    public abstract MidiFileFormat getMidiFileFormat(File file)
-            throws InvalidMidiDataException, IOException;
-
-    public abstract MidiFileFormat getMidiFileFormat(InputStream stream)
-            throws InvalidMidiDataException, IOException;
-
-    public abstract MidiFileFormat getMidiFileFormat(URL url)
-            throws InvalidMidiDataException, IOException;
-
-    public abstract Sequence getSequence(File file)
-            throws InvalidMidiDataException, IOException;
-
-    public abstract Sequence getSequence(InputStream stream)
-            throws InvalidMidiDataException, IOException;
-
-    public abstract Sequence getSequence(URL url)
-            throws InvalidMidiDataException, IOException;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiFileWriter.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiFileWriter.java
deleted file mode 100644
index e47d17c..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/MidiFileWriter.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi.spi;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import javax.sound.midi.Sequence;
-
-public abstract class MidiFileWriter {
-
-    public abstract int[] getMidiFileTypes();
-
-    public abstract int[] getMidiFileTypes(Sequence sequence);
-
-    public boolean isFileTypeSupported(int fileType) {
-        int[] supported = getMidiFileTypes();
-        for (int element : supported) {
-            if (fileType == element) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public boolean isFileTypeSupported(int fileType, Sequence sequence) {
-        int[] supported = getMidiFileTypes(sequence);
-        for (int element : supported) {
-            if (fileType == element) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public abstract int write(Sequence in, int fileType, File out)
-            throws IOException;
-
-    public abstract int write(Sequence in, int fileType, OutputStream out)
-            throws IOException;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/SoundbankReader.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/SoundbankReader.java
deleted file mode 100644
index 4fd195a..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/spi/SoundbankReader.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.midi.spi;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.Soundbank;
-
-public abstract class SoundbankReader {
-
-    public abstract Soundbank getSoundbank(File file)
-            throws InvalidMidiDataException, IOException;
-
-    public abstract Soundbank getSoundbank(InputStream stream)
-            throws InvalidMidiDataException, IOException;
-
-    public abstract Soundbank getSoundbank(URL url)
-            throws InvalidMidiDataException, IOException;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioFileFormat.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioFileFormat.java
deleted file mode 100644
index ce476f1..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioFileFormat.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-public class AudioFileFormat {
-
-    private AudioFileFormat.Type type;
-    private int byteLength = AudioSystem.NOT_SPECIFIED;
-    private AudioFormat format;
-    private int frameLength;
-    private HashMap<String, Object> prop;
-
-    protected AudioFileFormat(AudioFileFormat.Type type,
-            int byteLength,
-            AudioFormat format,
-            int frameLength) {
-        this.type = type;
-        this.byteLength = byteLength;
-        this.format = format;
-        this.frameLength = frameLength;
-    }
-    
-    public AudioFileFormat(AudioFileFormat.Type type,
-            AudioFormat format,
-            int frameLength) {
-        this.type = type;
-        this.format = format;
-        this.frameLength = frameLength;
-    }
-
-    public AudioFileFormat(AudioFileFormat.Type type,
-            AudioFormat format,
-            int frameLength,
-            Map<String,Object> properties) {
-        this.type = type;
-        this.format = format;
-        this.frameLength = frameLength;
-        prop = new HashMap<String, Object>();
-        prop.putAll(properties);
-    }
-    
-    public AudioFileFormat.Type getType() {
-        return type;
-    }
-    
-    public int getByteLength() {
-        return byteLength;
-    }
-
-    public AudioFormat getFormat() {
-        return format;
-    }
-    
-    public int getFrameLength() {
-        return frameLength;
-    }
-    
-    public Map<String,Object> properties() {
-        if (prop == null) {
-            return null;
-        }
-        return Collections.unmodifiableMap(prop);
-    }
-    
-    public Object getProperty(String key) {
-        if (prop == null) {
-            return null;
-        }
-        return prop.get(key);
-    }
-    
-    public String toString() {
-        return type + " (." + type.getExtension() + ") file, data format: " + format + //$NON-NLS-1$ //$NON-NLS-2$
-            " frame length: " + frameLength; //$NON-NLS-1$
-    }
-    
-    public static class Type {
-
-        private String name;
-
-        private String extension;
-
-        public static final Type AIFC = new Type("AIFF-C", "aifc"); //$NON-NLS-1$ //$NON-NLS-2$
-
-        public static final Type AIFF = new Type("AIFF", "aif"); //$NON-NLS-1$ //$NON-NLS-2$
-
-        public static final Type AU = new Type("AU", "au"); //$NON-NLS-1$ //$NON-NLS-2$
-
-        public static final Type SND = new Type("SND", "snd"); //$NON-NLS-1$ //$NON-NLS-2$
-
-        public static final Type WAVE = new Type("WAVE", "wav"); //$NON-NLS-1$ //$NON-NLS-2$
-
-        public Type(String name, String extension) {
-            this.name = name;
-            this.extension = extension;
-        }
-
-        /*
-         * according to the spec it should return true when objects are same but
-         * RI seem to compare internals
-         * 
-         * @see java.lang.Object#equals(java.lang.Object)
-         */
-        @Override
-        public final boolean equals(Object another) {
-            if (this == another) {
-                return true;
-            }
-
-            if (another == null || !(another instanceof Type)) {
-                return false;
-            }
-
-            Type obj = (Type) another;
-            return (name == null ? obj.name == null : name.equals(obj.name))
-                    && (extension == null ? obj.extension == null : extension
-                            .equals(obj.extension));
-        }
-
-        public String getExtension() {
-            return extension;
-        }
-
-        @Override
-        public final int hashCode() {
-            return (name == null ? 0 : name.hashCode()) + 
-                    (extension == null ? 0 : extension.hashCode());
-        }
-
-        @Override
-        public final String toString() {
-            return name;
-        }
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioFormat.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioFormat.java
deleted file mode 100644
index 721ed6a..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioFormat.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-public class AudioFormat {
-    public static class Encoding {
-
-        public static final Encoding ALAW = new Encoding("ALAW"); //$NON-NLS-1$
-
-        public static final Encoding PCM_SIGNED = new Encoding("PCM_SIGNED"); //$NON-NLS-1$
-
-        public static final Encoding PCM_UNSIGNED = new Encoding("PCM_UNSIGNED"); //$NON-NLS-1$
-
-        public static final Encoding ULAW = new Encoding("ULAW"); //$NON-NLS-1$
-
-        private String name;
-
-        public Encoding(String name) {
-            this.name = name;
-        }
-
-        @Override
-        public boolean equals(Object another) {
-            if (this == another) {
-                return true;
-            }
-
-            if (another == null || !(another instanceof Encoding)) {
-                return false;
-            }
-
-            Encoding obj = (Encoding) another;
-            return name == null ? obj.name == null : name.equals(obj.name);
-        }
-
-        @Override
-        public final int hashCode() {
-            return name == null ? 0 : name.hashCode();
-        }
-
-        @Override
-        public final String toString() {
-            return name;
-        }
-    }
-
-    protected boolean bigEndian;
-
-    protected int channels;
-
-    protected Encoding encoding;
-
-    protected float frameRate;
-
-    protected int frameSize;
-
-    protected float sampleRate;
-
-    protected int sampleSizeInBits;
-
-    private HashMap<String, Object> prop;
-
-    public AudioFormat(AudioFormat.Encoding encoding,
-            float sampleRate,
-            int sampleSizeInBits,
-            int channels,
-            int frameSize,
-            float frameRate,
-            boolean bigEndian) {
-
-        this.encoding = encoding;
-        this.sampleRate = sampleRate;
-        this.sampleSizeInBits = sampleSizeInBits;
-        this.channels = channels;
-        this.frameSize = frameSize;
-        this.frameRate = frameRate;
-        this.bigEndian = bigEndian;
-
-    }
-
-    public AudioFormat(AudioFormat.Encoding encoding,
-            float sampleRate,
-            int sampleSizeInBits,
-            int channels,
-            int frameSize,
-            float frameRate,
-            boolean bigEndian,
-            Map<String,Object> properties) {
-
-        this.encoding = encoding;
-        this.sampleRate = sampleRate;
-        this.sampleSizeInBits = sampleSizeInBits;
-        this.channels = channels;
-        this.frameSize = frameSize;
-        this.frameRate = frameRate;
-        this.bigEndian = bigEndian;
-        prop = new HashMap<String, Object>();
-        prop.putAll(properties);
-
-    }
-
-    public AudioFormat(float sampleRate,
-            int sampleSizeInBits,
-            int channels,
-            boolean signed,
-            boolean bigEndian) {
-
-        this.encoding = (signed?  Encoding.PCM_SIGNED : Encoding.PCM_UNSIGNED);
-        this.sampleRate = sampleRate;
-        this.sampleSizeInBits = sampleSizeInBits;
-        this.channels = channels;
-        this.frameSize = sampleSizeInBits >> 3;
-        if ((sampleSizeInBits & 0x7) != 0) {
-            this.frameSize++;
-        }
-        this.frameSize *= channels;
-        this.frameRate = sampleRate;
-        this.bigEndian = bigEndian;
-
-    }
-
-    public Encoding getEncoding() {
-        return encoding;
-    }
-
-    public float getSampleRate() {
-        return sampleRate;
-    }
-    
-    public int getSampleSizeInBits() {
-        return sampleSizeInBits;
-    }
-
-    public int getChannels() {
-        return channels;
-    }
-
-    public int getFrameSize() {
-        return frameSize;
-    }
-
-    public float getFrameRate() {
-        return frameRate;
-    }
-
-    public boolean isBigEndian() {
-        return bigEndian;
-    }
-
-    public Map<String,Object> properties() {
-        if (prop != null) {
-            return Collections.unmodifiableMap(prop);
-        } else {
-            return Collections.emptyMap();
-        }
-    }
-
-    public Object getProperty(String key) {
-        if (prop == null) {
-            return null;
-        }
-        return prop.get(key);
-    }
-
-    public boolean matches(AudioFormat format) {
-        if (!encoding.equals(format.getEncoding()) ||
-                channels != format.getChannels() ||
-                sampleSizeInBits != format.getSampleSizeInBits() ||
-                frameSize != format.getFrameSize()) {
-            return false;
-        }
-        if (format.getSampleRate() != AudioSystem.NOT_SPECIFIED &&
-                sampleRate != format.getSampleRate()) {
-            return false;
-        }
-        
-        if (format.getFrameRate() != AudioSystem.NOT_SPECIFIED &&
-                frameRate != format.getFrameRate()) {
-            return false;
-        }
-        
-        if ((sampleSizeInBits > 8) 
-                && (bigEndian != format.isBigEndian())) {
-            return false;
-        }
-        return true;
-        
-    }
-
-    public String toString() {
-
-        String ch;
-        switch (channels) {
-        case 1:
-            ch = "mono,"; //$NON-NLS-1$
-            break;
-        case 2:
-            ch = "stereo,"; //$NON-NLS-1$
-        default:
-            ch = channels + " channels, "; //$NON-NLS-1$
-        }       
-
-        return encoding + " " + sampleRate + " Hz, " + sampleSizeInBits + " bit, " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-            + ch + frameSize + " bytes/frame, " + frameRate + " frames/second"; //$NON-NLS-1$ //$NON-NLS-2$
-    }
-    
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioInputStream.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioInputStream.java
deleted file mode 100644
index 3105f94..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioInputStream.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class AudioInputStream extends InputStream {
-
-    protected AudioFormat format;
-
-    protected long frameLength;
-
-    protected long framePos;
-
-    protected int frameSize;
-
-    private InputStream stream;
-
-    private TargetDataLine line;
-
-    private byte[] oneByte = new byte[1];
-
-    private long marketFramePos;
-
-    public AudioInputStream(InputStream stream, AudioFormat format, long length) {
-        this.stream = stream;
-        this.format = format;
-        this.frameLength = length;
-        this.frameSize = format.getFrameSize();
-    }
-
-    public AudioInputStream(TargetDataLine line) {
-        this.line = line;
-        this.format = line.getFormat();
-        this.frameLength = AudioSystem.NOT_SPECIFIED; //TODO
-        this.frameSize = this.format.getFrameSize();
-    }
-
-    public AudioFormat getFormat() {
-        return format;
-    }
-
-    public long getFrameLength() {
-        return frameLength;
-    }
-
-    public int read() throws IOException {
-        if (frameSize != 1) {
-            // sound.0C=Frame size must be one byte
-            throw new IOException(Messages.getString("sound.0C")); //$NON-NLS-1$
-        }
-        int res;
-        if (stream != null) { // InputStream
-            if (framePos == frameLength) {
-                return 0;
-            }
-            res = stream.read();
-            if (res == -1) {
-                return -1;
-            }
-            framePos += 1;
-            return res;
-        } else { // TargetDataLine
-            if (line.read(oneByte, 0, 1) == 0) {
-                return -1;
-            }
-            framePos = line.getLongFramePosition();
-            return oneByte[0];
-        }
-    }
-
-    public int read(byte[] b) throws IOException {
-        return read(b, 0, b.length);
-    }
-
-    public int read(byte[] b, int off, int len) throws IOException {
-        int l = Math.min(len, (int) ((frameLength - framePos) * frameSize));
-        l = l - (l % frameSize);
-        if (l == 0) {
-            return 0;
-        }
-        int res;
-        if (stream != null) { // InputStream
-            res = stream.read(b, off, l);
-            if (res == -1) {
-                return -1;
-            }
-            framePos = framePos + res / frameSize;
-            return res;
-        } else { // TargetDataLine
-            res = line.read(b, off, l);
-            if (res == 0) {
-                return -1;
-            }
-            framePos = line.getLongFramePosition();
-            return res;
-        }
-
-    }
-
-    public long skip(long n) throws IOException {
-
-        if (n < frameSize) {
-            return 0;
-        }
-        byte[] skipBuf = new byte[frameSize];
-        long skipped = 0;
-        while (skipped < n) {
-            int read = read(skipBuf, 0, frameSize);
-            if (read == -1) {
-                return skipped;
-            }
-            skipped += read;
-            if (n - skipped < frameSize) {
-                return skipped;
-            }
-        }
-        return skipped;
-
-    }
-
-    public int available() throws IOException {
-        if (stream != null) { // InputStream
-            return Math.min(stream.available(),
-                    (int)((frameLength - framePos) * frameSize));
-        } else { // TargetDataLine
-            return line.available();
-        }
-    }
-
-    public void close() throws IOException {
-        if (stream != null) { // InputStream
-            stream.close();
-        } else { // TargetDataLine
-            line.close();
-        }
-    }
-
-    public void mark(int readlimit) {
-        if (stream != null) { //InputStream
-            stream.mark(readlimit);
-            marketFramePos = framePos;
-        } else { // TargetDataLine
-            // do nothing
-        }
-    }
-
-    public void reset() throws IOException {
-        if (stream != null) { //InputStream
-            stream.reset();
-            framePos = marketFramePos;
-        } else { // TargetDataLine
-            // do nothing
-        }
-    }
-
-    public boolean markSupported() {
-        if (stream != null) { //InputStream
-            return stream.markSupported();
-        } else { // TargetDataLine
-            return false;
-        }
-    }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioPermission.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioPermission.java
deleted file mode 100644
index 04ddd94..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioPermission.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.security.BasicPermission;
-
-public class AudioPermission extends BasicPermission {
-
-    private static final long serialVersionUID = -5518053473477801126L;
-
-    public AudioPermission(String name) {
-        super(name);
-    }
-
-    public AudioPermission(String name, String actions) {
-        super(name, actions);
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioSystem.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioSystem.java
deleted file mode 100644
index c279c17..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/AudioSystem.java
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Iterator;
-import java.util.Properties;
-
-import javax.sound.sampled.spi.AudioFileReader;
-import javax.sound.sampled.spi.AudioFileWriter;
-import javax.sound.sampled.spi.FormatConversionProvider;
-import javax.sound.sampled.spi.MixerProvider;
-
-import org.apache.harmony.sound.utils.ProviderService;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class AudioSystem {
-
-    public static final int NOT_SPECIFIED = -1;
-
-    private final static String audioFileReaderPath = "META-INF/services/javax.sound.sampled.spi.AudioFileReader"; //$NON-NLS-1$
-
-    private final static String audioFileWriterPath = "META-INF/services/javax.sound.sampled.spi.AudioFileWriter"; //$NON-NLS-1$
-
-    private final static String formatConversionProviderPath = "META-INF/services/javax.sound.sampled.spi.FormatConversionProvider"; //$NON-NLS-1$
-
-    private final static String mixerProviderPath = "META-INF/services/javax.sound.sampled.spi.MixerProvider"; //$NON-NLS-1$
-
-    private final static String CLIP = "javax.sound.sampled.Clip"; //$NON-NLS-1$
-
-    private final static String PORT = "javax.sound.sampled.Port"; //$NON-NLS-1$
-
-    private final static String SOURCEDATALINE = "javax.sound.sampled.SourceDataLine"; //$NON-NLS-1$
-
-    private final static String TARGETDATALINE = "javax.sound.sampled.TargetDataLine"; //$NON-NLS-1$
-
-    public static Mixer.Info[] getMixerInfo() {
-        List<Mixer.Info> result = new ArrayList<Mixer.Info>();
-        for (Iterator providers = ProviderService.getProviders(
-                mixerProviderPath).iterator(); providers.hasNext();) {
-            try {
-                Mixer.Info[] infos = ((MixerProvider) (providers.next()))
-                        .getMixerInfo();
-                for (Mixer.Info info : infos) {
-                    result.add(info);
-                }
-            } catch (ClassCastException e) {}
-        }
-        Mixer.Info[] temp = new Mixer.Info[result.size()];
-        return result.toArray(temp);
-    }
-
-    public static Mixer getMixer(Mixer.Info info) {
-        Mixer.Info[] infos;
-        Mixer.Info inf;
-        if (info == null) {
-            infos = getMixerInfo();
-            if (infos == null) {
-                throw new IllegalArgumentException(
-                        "No system default mixer installed"); //$NON-NLS-1$
-            }
-            inf = infos[0];
-        } else {
-            inf = info;
-        }
-
-        for (Iterator providers = ProviderService.getProviders(
-                mixerProviderPath).iterator(); providers.hasNext();) {
-            try {
-                return ((MixerProvider) (providers.next())).getMixer(inf);
-            } catch (ClassCastException e) {} catch (IllegalArgumentException e) {}
-        }
-        throw new IllegalArgumentException("Mixer not supported: " + inf); //$NON-NLS-1$
-    }
-
-    public static Line.Info[] getSourceLineInfo(Line.Info info) {
-        List<Line.Info> result = new ArrayList<Line.Info>();
-        for (Iterator providers = ProviderService.getProviders(
-                mixerProviderPath).iterator(); providers.hasNext();) {
-            try {
-                MixerProvider pr = (MixerProvider) providers.next();
-                Mixer.Info[] mixinfos = pr.getMixerInfo();
-                for (Mixer.Info mixinfo : mixinfos) {
-                    Mixer mix = pr.getMixer(mixinfo);
-                    Line.Info[] linfos = mix.getSourceLineInfo(info);
-                    for (Line.Info linfo : linfos) {
-                        result.add(linfo);
-                    }
-                }
-            } catch (ClassCastException e) {}
-        }
-        Line.Info[] temp = new Line.Info[result.size()];
-        return result.toArray(temp);
-    }
-
-    public static Line.Info[] getTargetLineInfo(Line.Info info) {
-        List<Line.Info> result = new ArrayList<Line.Info>();
-        for (Iterator providers = ProviderService.getProviders(
-                mixerProviderPath).iterator(); providers.hasNext();) {
-            try {
-                MixerProvider pr = (MixerProvider) providers.next();
-                Mixer.Info[] mixinfos = pr.getMixerInfo();
-                for (Mixer.Info mixinfo : mixinfos) {
-                    Mixer mix = pr.getMixer(mixinfo);
-                    Line.Info[] linfos = mix.getTargetLineInfo(info);
-                    for (Line.Info linfo : linfos) {
-                        result.add(linfo);
-                    }
-                }
-            } catch (ClassCastException e) {}
-        }
-        Line.Info[] temp = new Line.Info[result.size()];
-        return result.toArray(temp);
-    }
-
-    public static boolean isLineSupported(Line.Info info) {
-
-        for (Iterator providers = ProviderService.getProviders(
-                mixerProviderPath).iterator(); providers.hasNext();) {
-            try {
-                MixerProvider pr = (MixerProvider) providers.next();
-                Mixer.Info[] mixinfos = pr.getMixerInfo();
-                for (Mixer.Info mixinfo : mixinfos) {
-                    Mixer mix = pr.getMixer(mixinfo);
-                    if (mix.isLineSupported(info)) {
-                        return true;
-                    }
-                }
-            } catch (ClassCastException e) {}
-        }
-        return false;
-    }
-
-    private static Mixer getMixer(String propVal, Line.Info info,
-            List<?> mixerProviders) {
-
-        int index = propVal.indexOf("#"); //$NON-NLS-1$
-        String className;
-        String mixName;
-        if (index == -1) {
-            className = propVal.trim();
-            mixName = ""; //$NON-NLS-1$
-        } else {
-            className = propVal.substring(0, index).trim();
-            if (index == propVal.length()) {
-                mixName = ""; //$NON-NLS-1$
-            } else {
-                mixName = propVal.substring(index + 1).trim();
-            }
-        }
-        Mixer.Info[] minfos = null;
-        if (!className.equals("")) { //$NON-NLS-1$
-            for (Iterator providers = mixerProviders.iterator(); providers
-                    .hasNext();) {
-                try {
-                    MixerProvider pr = (MixerProvider) (providers.next());
-                    if (className.equals(pr.getClass().getName())) {
-                        minfos = pr.getMixerInfo();
-                        break;
-                    }
-                } catch (ClassCastException e) {}
-            }
-        }
-        if (minfos == null) {
-            minfos = getMixerInfo();
-        }
-
-        if (!mixName.equals("")) { //$NON-NLS-1$
-            for (Mixer.Info minfo : minfos) {
-                if (mixName.equals(minfo.getName())) {
-                    return getMixer(minfo);
-                }
-            }
-        }
-        if (minfos.length > 0) {
-            return getMixer(minfos[0]);
-        }
-        return null;
-    }
-
-    public static Line getLine(Line.Info info) throws LineUnavailableException {
-        String propName = null;
-        Class lineClass = info.getLineClass();
-
-        if (Clip.class.isAssignableFrom(lineClass)) {
-            propName = CLIP;
-        } else if (Port.class.isAssignableFrom(lineClass)) {
-            propName = PORT;
-        } else if (SourceDataLine.class.isAssignableFrom(lineClass)) {
-            propName = SOURCEDATALINE;
-        } else if (TargetDataLine.class.isAssignableFrom(lineClass)) {
-            propName = TARGETDATALINE;
-        }
-        return getLine(propName, info);
-    }
-
-    private static Line getLine(String propName, Line.Info info)
-            throws LineUnavailableException {
-
-        List<?> mixerProviders = ProviderService
-                .getProviders(mixerProviderPath);
-
-        if (propName != null) {
-            String propVal = System.getProperty(propName);
-            if (propVal != null) {
-                Mixer m = getMixer(propVal, info, mixerProviders);
-                if (m != null) {
-                    Line l = m.getLine(info);
-                    if (l != null) {
-                        return l;
-                    }
-                }
-            }
-
-            Properties soundProperties = ProviderService.getSoundProperties();
-            propVal = soundProperties.getProperty(propName);
-            if (propVal != null) {
-                Mixer m = getMixer(propVal, info, mixerProviders);
-                if (m != null) {
-                    Line l = m.getLine(info);
-                    if (l != null) {
-                        return l;
-                    }
-                }
-            }
-        }
-
-        for (Iterator providers = ProviderService.getProviders(
-                mixerProviderPath).iterator(); providers.hasNext();) {
-            try {
-                MixerProvider pr = (MixerProvider) (providers.next());
-                Mixer.Info[] mixinfos = pr.getMixerInfo();
-                for (Mixer.Info mixinfo : mixinfos) {
-                    try {
-                        Mixer mix = pr.getMixer(mixinfo);
-                        return mix.getLine(info);
-                    } catch (IllegalArgumentException e) {
-                        // continue
-                    }
-                }
-            } catch (ClassCastException e) {}
-        }
-        
-        // BEGIN android-added
-        if (CLIP.equals(propName)) {
-            try {
-                return (Clip)(Class.forName("com.android.internal.sound.sampled.AndroidClip").newInstance());
-            } catch (Exception ex) {
-                // Ignore
-            }
-        }
-        // END android-added
-        
-        // sound.11=Could not get line
-        throw new IllegalArgumentException(Messages.getString("sound.11")); //$NON-NLS-1$
-    }
-
-    public static Clip getClip() throws LineUnavailableException {
-        return (Clip) getLine(new Line.Info(Clip.class));
-    }
-
-    public static Clip getClip(Mixer.Info mixerInfo)
-            throws LineUnavailableException {
-        return (Clip) (getMixer(mixerInfo).getLine(new Line.Info(Clip.class)));
-    }
-
-    public static SourceDataLine getSourceDataLine(AudioFormat format)
-            throws LineUnavailableException {
-        SourceDataLine line = (SourceDataLine) getLine(new Line.Info(
-                SourceDataLine.class));
-        line.open(format);
-        return line;
-    }
-
-    public static SourceDataLine getSourceDataLine(AudioFormat format,
-            Mixer.Info mixerinfo) throws LineUnavailableException {
-
-        SourceDataLine line = (SourceDataLine) getMixer(mixerinfo).getLine(
-                new Line.Info(SourceDataLine.class));
-        line.open(format);
-        return line;
-    }
-
-    public static TargetDataLine getTargetDataLine(AudioFormat format)
-            throws LineUnavailableException {
-        TargetDataLine line = (TargetDataLine) getLine(new Line.Info(
-                TargetDataLine.class));
-        line.open(format);
-        return line;
-    }
-
-    public static TargetDataLine getTargetDataLine(AudioFormat format,
-            Mixer.Info mixerinfo) throws LineUnavailableException {
-
-        TargetDataLine line = (TargetDataLine) getMixer(mixerinfo).getLine(
-                new Line.Info(TargetDataLine.class));
-        line.open(format);
-        return line;
-    }
-
-    public static AudioFormat.Encoding[] getTargetEncodings(
-            AudioFormat.Encoding sourceEncoding) {
-
-        List<AudioFormat.Encoding> result = new ArrayList<AudioFormat.Encoding>();
-        for (Iterator providers = ProviderService.getProviders(
-                formatConversionProviderPath).iterator(); providers.hasNext();) {
-            try {
-                FormatConversionProvider pr = (FormatConversionProvider) providers
-                        .next();
-                if (!pr.isSourceEncodingSupported(sourceEncoding)) {
-                    continue;
-                }
-                AudioFormat.Encoding[] encodings = pr.getTargetEncodings();
-                for (AudioFormat.Encoding encoding : encodings) {
-                    result.add(encoding);
-                }
-            } catch (ClassCastException e) {}
-        }
-        AudioFormat.Encoding[] temp = new AudioFormat.Encoding[result.size()];
-        return result.toArray(temp);
-    }
-
-    public static AudioFormat.Encoding[] getTargetEncodings(
-            AudioFormat sourceFormat) {
-
-        List<AudioFormat.Encoding> result = new ArrayList<AudioFormat.Encoding>();
-        for (Iterator providers = ProviderService.getProviders(
-                formatConversionProviderPath).iterator(); providers.hasNext();) {
-            try {
-                AudioFormat.Encoding[] encodings = ((FormatConversionProvider) (providers
-                        .next())).getTargetEncodings(sourceFormat);
-                for (AudioFormat.Encoding encoding : encodings) {
-                    result.add(encoding);
-                }
-            } catch (ClassCastException e) {}
-        }
-        AudioFormat.Encoding[] temp = new AudioFormat.Encoding[result.size()];
-        return result.toArray(temp);
-    }
-
-    public static boolean isConversionSupported(
-            AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
-
-        for (Iterator providers = ProviderService.getProviders(
-                formatConversionProviderPath).iterator(); providers.hasNext();) {
-            if (((FormatConversionProvider) (providers.next()))
-                    .isConversionSupported(targetEncoding, sourceFormat)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static AudioInputStream getAudioInputStream(
-            AudioFormat.Encoding targetEncoding, AudioInputStream sourceStream) {
-
-        if (sourceStream.getFormat().getEncoding().equals(targetEncoding)) {
-            return sourceStream;
-        }
-        for (Iterator providers = ProviderService.getProviders(
-                formatConversionProviderPath).iterator(); providers.hasNext();) {
-            try {
-                return ((FormatConversionProvider) (providers.next()))
-                        .getAudioInputStream(targetEncoding, sourceStream);
-            } catch (ClassCastException e) {} catch (IllegalArgumentException e) {}
-        }
-        // sound.12=Could not get audio input stream from source stream
-        throw new IllegalArgumentException(Messages.getString("sound.12")); //$NON-NLS-1$
-    }
-
-    public static AudioFormat[] getTargetFormats(
-            AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
-
-        List<AudioFormat> result = new ArrayList<AudioFormat>();
-        for (Iterator providers = ProviderService.getProviders(
-                formatConversionProviderPath).iterator(); providers.hasNext();) {
-            try {
-                AudioFormat[] formats = ((FormatConversionProvider) (providers
-                        .next()))
-                        .getTargetFormats(targetEncoding, sourceFormat);
-                for (AudioFormat format : formats) {
-                    result.add(format);
-                }
-            } catch (ClassCastException e) {}
-        }
-        AudioFormat[] temp = new AudioFormat[result.size()];
-        return result.toArray(temp);
-    }
-
-    public static boolean isConversionSupported(AudioFormat targetFormat,
-            AudioFormat sourceFormat) {
-
-        for (Iterator providers = ProviderService.getProviders(
-                formatConversionProviderPath).iterator(); providers.hasNext();) {
-            if (((FormatConversionProvider) (providers.next()))
-                    .isConversionSupported(targetFormat, sourceFormat)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static AudioInputStream getAudioInputStream(
-            AudioFormat targetFormat, AudioInputStream sourceStream) {
-
-        if (sourceStream.getFormat().matches(targetFormat)) {
-            return sourceStream;
-        }
-        for (Iterator providers = ProviderService.getProviders(
-                formatConversionProviderPath).iterator(); providers.hasNext();) {
-            try {
-                return ((FormatConversionProvider) (providers.next()))
-                        .getAudioInputStream(targetFormat, sourceStream);
-            } catch (ClassCastException e) {} catch (IllegalArgumentException e) {}
-        }
-        // sound.13=Could not get audio input stream from source stream
-        throw new IllegalArgumentException(Messages.getString("sound.13")); //$NON-NLS-1$
-    }
-
-    public static AudioFileFormat getAudioFileFormat(InputStream stream)
-            throws UnsupportedAudioFileException, IOException {
-
-        for (Iterator providers = ProviderService.getProviders(
-                audioFileReaderPath).iterator(); providers.hasNext();) {
-            try {
-                return ((AudioFileReader) (providers.next()))
-                        .getAudioFileFormat(stream);
-            } catch (ClassCastException e) {} catch (UnsupportedAudioFileException e) {}
-        }
-        // sound.14=File is not a supported file type
-        throw new UnsupportedAudioFileException(Messages.getString("sound.14")); //$NON-NLS-1$
-    }
-
-    public static AudioFileFormat getAudioFileFormat(URL url)
-            throws UnsupportedAudioFileException, IOException {
-
-        for (Iterator providers = ProviderService.getProviders(
-                audioFileReaderPath).iterator(); providers.hasNext();) {
-            try {
-                return ((AudioFileReader) (providers.next()))
-                        .getAudioFileFormat(url);
-            } catch (ClassCastException e) {} catch (UnsupportedAudioFileException e) {}
-        }
-        // sound.14=File is not a supported file type
-        throw new UnsupportedAudioFileException(Messages.getString("sound.14")); //$NON-NLS-1$
-    }
-
-    public static AudioFileFormat getAudioFileFormat(File file)
-            throws UnsupportedAudioFileException, IOException {
-
-        for (Iterator providers = ProviderService.getProviders(
-                audioFileReaderPath).iterator(); providers.hasNext();) {
-            try {
-                return ((AudioFileReader) (providers.next()))
-                        .getAudioFileFormat(file);
-            } catch (ClassCastException e) {} catch (UnsupportedAudioFileException e) {}
-        }
-        // sound.14=File is not a supported file type
-        throw new UnsupportedAudioFileException(Messages.getString("sound.14")); //$NON-NLS-1$
-    }
-
-    public static AudioInputStream getAudioInputStream(InputStream stream)
-            throws UnsupportedAudioFileException, IOException {
-
-        if (stream instanceof AudioInputStream) {
-            return (AudioInputStream) stream;
-        }
-        for (Iterator providers = ProviderService.getProviders(
-                audioFileReaderPath).iterator(); providers.hasNext();) {
-            try {
-                return ((AudioFileReader) (providers.next()))
-                        .getAudioInputStream(stream);
-            } catch (ClassCastException e) {} catch (UnsupportedAudioFileException e) {}
-        }
-        // BEGIN android-added
-        try {
-            AudioFileReader reader = (AudioFileReader)(Class.forName("com.android.internal.sound.sampled.AndroidAudioFileReader").newInstance());
-            return reader.getAudioInputStream(stream);
-        } catch (Exception ex) {
-            // Ignore
-        }
-        // END android-added
-        // sound.15=Could not get audio input stream from input stream
-        throw new UnsupportedAudioFileException(Messages.getString("sound.15")); //$NON-NLS-1$
-    }
-
-    public static AudioInputStream getAudioInputStream(URL url)
-            throws UnsupportedAudioFileException, IOException {
-
-        for (Iterator providers = ProviderService.getProviders(
-                audioFileReaderPath).iterator(); providers.hasNext();) {
-            try {
-                return ((AudioFileReader) (providers.next()))
-                        .getAudioInputStream(url);
-            } catch (ClassCastException e) {} catch (UnsupportedAudioFileException e) {}
-        }
-        // BEGIN android-added
-        try {
-            AudioFileReader reader = (AudioFileReader)(Class.forName("com.android.internal.sound.sampled.AndroidAudioFileReader").newInstance());
-            return reader.getAudioInputStream(url);
-        } catch (Exception ex) {
-            // Ignore
-        }
-        // END android-added
-        // sound.16=Could not get audio input stream from input URL
-        throw new UnsupportedAudioFileException(Messages.getString("sound.16")); //$NON-NLS-1$
-    }
-
-    public static AudioInputStream getAudioInputStream(File file)
-            throws UnsupportedAudioFileException, IOException {
-
-        for (Iterator providers = ProviderService.getProviders(
-                audioFileReaderPath).iterator(); providers.hasNext();) {
-            try {
-                return ((AudioFileReader) (providers.next()))
-                        .getAudioInputStream(file);
-            } catch (ClassCastException e) {} catch (UnsupportedAudioFileException e) {}
-        }
-        // BEGIN android-added
-        try {
-            AudioFileReader reader = (AudioFileReader)(Class.forName("com.android.internal.sound.sampled.AndroidAudioFileReader").newInstance());
-            return reader.getAudioInputStream(file);
-        } catch (Exception ex) {
-            // Ignore
-        }
-        // END android-added
-        // sound.17=Could not get audio input stream from input file
-        throw new UnsupportedAudioFileException(Messages.getString("sound.17")); //$NON-NLS-1$
-    }
-
-    public static AudioFileFormat.Type[] getAudioFileTypes() {
-        List<AudioFileFormat.Type> result = new ArrayList<AudioFileFormat.Type>();
-        for (Iterator providers = ProviderService.getProviders(
-                audioFileWriterPath).iterator(); providers.hasNext();) {
-            try {
-                AudioFileFormat.Type[] types = ((AudioFileWriter) (providers
-                        .next())).getAudioFileTypes();
-                for (AudioFileFormat.Type type : types) {
-                    result.add(type);
-                }
-            } catch (ClassCastException e) {}
-        }
-        AudioFileFormat.Type[] temp = new AudioFileFormat.Type[result.size()];
-        return result.toArray(temp);
-    }
-
-    public static boolean isFileTypeSupported(AudioFileFormat.Type fileType) {
-
-        for (Iterator providers = ProviderService.getProviders(
-                audioFileWriterPath).iterator(); providers.hasNext();) {
-            if (((AudioFileWriter) (providers.next()))
-                    .isFileTypeSupported(fileType)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static AudioFileFormat.Type[] getAudioFileTypes(
-            AudioInputStream stream) {
-        List<AudioFileFormat.Type> result = new ArrayList<AudioFileFormat.Type>();
-        for (Iterator providers = ProviderService.getProviders(
-                audioFileWriterPath).iterator(); providers.hasNext();) {
-            try {
-                AudioFileFormat.Type[] types = ((AudioFileWriter) (providers
-                        .next())).getAudioFileTypes(stream);
-                for (AudioFileFormat.Type type : types) {
-                    result.add(type);
-                }
-            } catch (ClassCastException e) {}
-        }
-        AudioFileFormat.Type[] temp = new AudioFileFormat.Type[result.size()];
-        return result.toArray(temp);
-    }
-
-    public static boolean isFileTypeSupported(AudioFileFormat.Type fileType,
-            AudioInputStream stream) {
-
-        for (Iterator providers = ProviderService.getProviders(
-                audioFileWriterPath).iterator(); providers.hasNext();) {
-            if (((AudioFileWriter) (providers.next())).isFileTypeSupported(
-                    fileType, stream)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static int write(AudioInputStream stream,
-            AudioFileFormat.Type fileType, OutputStream out) throws IOException {
-        AudioFileWriter writer;
-        for (Iterator providers = ProviderService.getProviders(
-                audioFileWriterPath).iterator(); providers.hasNext();) {
-            writer = (AudioFileWriter) (providers.next());
-            if (writer.isFileTypeSupported(fileType, stream)) {
-                return writer.write(stream, fileType, out);
-            }
-        }
-        // sound.18=Type is not supported
-        throw new IllegalArgumentException(Messages.getString("sound.18")); //$NON-NLS-1$
-    }
-
-    public static int write(AudioInputStream stream,
-            AudioFileFormat.Type fileType, File out) throws IOException {
-        AudioFileWriter writer;
-        for (Iterator providers = ProviderService.getProviders(
-                audioFileWriterPath).iterator(); providers.hasNext();) {
-            writer = (AudioFileWriter) (providers.next());
-            if (writer.isFileTypeSupported(fileType, stream)) {
-                return writer.write(stream, fileType, out);
-            }
-        }
-        // sound.18=Type is not supported
-        throw new IllegalArgumentException(Messages.getString("sound.18")); //$NON-NLS-1$
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/BooleanControl.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/BooleanControl.java
deleted file mode 100644
index 5ab87fb..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/BooleanControl.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public abstract class BooleanControl extends Control {
-
-    public static class Type extends Control.Type {
-        public static final Type APPLY_REVERB = new Type("Apply Reverb"); //$NON-NLS-1$
-
-        public static final Type MUTE = new Type("Mute"); //$NON-NLS-1$
-
-        protected Type(String name) {
-            super(name);
-        }
-    }
-
-    private boolean value;
-
-    private String trueStateLabel;
-
-    private String falseStateLabel;
-
-    protected BooleanControl(BooleanControl.Type type, boolean initialValue,
-            String trueStateLabel, String falseStateLabel) {
-        super(type);
-        this.value = initialValue;
-        this.trueStateLabel = trueStateLabel;
-        this.falseStateLabel = falseStateLabel;
-    }
-
-    protected BooleanControl(BooleanControl.Type type, boolean initialValue) {
-        this(type, initialValue, "true", "false"); //$NON-NLS-1$ //$NON-NLS-2$
-    }
-
-    public void setValue(boolean value) {
-        this.value = value;
-    }
-
-    public boolean getValue() {
-        return this.value;
-    }
-
-    public String getStateLabel(boolean state) {
-        if (state) {
-            return this.trueStateLabel;
-        } else {
-            return this.falseStateLabel;
-        }
-    }
-
-    public String toString() {
-        return getType() + " Control with current value: " + getStateLabel(value); //$NON-NLS-1$
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Clip.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/Clip.java
deleted file mode 100644
index 0e65b59..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Clip.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.io.IOException;
-
-public interface Clip extends DataLine {
-    static final int LOOP_CONTINUOUSLY = -1;
-
-    int getFrameLength();
-
-    long getMicrosecondLength();
-
-    void loop(int count);
-
-    void open(AudioFormat format, byte[] data, int offset, int bufferSize)
-            throws LineUnavailableException;
-
-    void open(AudioInputStream stream) throws LineUnavailableException,
-            IOException;
-
-    void setFramePosition(int frames);
-
-    void setLoopPoints(int start, int end);
-
-    void setMicrosecondPosition(long microseconds);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/CompoundControl.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/CompoundControl.java
deleted file mode 100644
index 5862761..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/CompoundControl.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public abstract class CompoundControl extends Control {
-    public static class Type extends Control.Type {
-        protected Type(String name) {
-            super(name);
-        }
-    }
-
-    private Control[] memberControls;
-
-    protected CompoundControl(CompoundControl.Type type,
-            Control[] memberControls) {
-        super(type);
-        this.memberControls = memberControls;
-    }
-
-    public Control[] getMemberControls() {
-        return this.memberControls;
-    }
-
-    public String toString() {
-        return getType() + "CompoundControl containing "  //$NON-NLS-1$
-            + String.valueOf(memberControls) + " Controls."; //$NON-NLS-1$
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Control.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/Control.java
deleted file mode 100644
index b6128e8..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Control.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public abstract class Control {
-
-    public static class Type {
-
-        private String name;
-
-        public Type(String name) {
-            this.name = name;
-        }
-
-        @Override
-        public boolean equals(Object another) {
-            if (this == another) {
-                return true;
-            }
-
-            if (another == null || !(another instanceof Type)) {
-                return false;
-            }
-
-            Type obj = (Type) another;
-            return name == null ? obj.name == null : name.equals(obj.name);
-        }
-
-        @Override
-        public final int hashCode() {
-            return name == null ? 0 : name.hashCode();
-        }
-
-        @Override
-        public final String toString() {
-            return name;
-        }
-    }
-
-    private Type type;
-
-    protected Control(Type type) {
-        this.type = type;
-    }
-
-    public Type getType() {
-        return type;
-    }
-
-    public String toString() {
-        return type + " Control"; //$NON-NLS-1$
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/DataLine.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/DataLine.java
deleted file mode 100644
index e37ea3f..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/DataLine.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public interface DataLine extends Line {
-
-    class Info extends Line.Info {
-        private AudioFormat[] formats;
-        private int minBufferSize;
-        private int maxBufferSize;
-        
-        public Info(Class <?> lineClass, AudioFormat format) {
-            super(lineClass);
-
-            this.formats = new AudioFormat[] { format };
-            this.minBufferSize = AudioSystem.NOT_SPECIFIED;
-            this.maxBufferSize = AudioSystem.NOT_SPECIFIED;
-        }
-
-        public Info(Class <?> lineClass, AudioFormat[] formats, int minBufferSize, int maxBufferSize) {
-            super(lineClass);
-
-            this.formats = formats;
-            this.minBufferSize = minBufferSize;
-            this.maxBufferSize = maxBufferSize;
-        }
-
-        public Info(Class <?> lineClass, AudioFormat format, int bufferSize) {
-            super(lineClass);
-
-            this.formats = new AudioFormat[] { format };
-            this.minBufferSize = bufferSize;
-            this.maxBufferSize = bufferSize;
-        }
-
-        public AudioFormat[] getFormats(){
-            return formats;
-        }
-        
-        public boolean isFormatSupported(AudioFormat format) {
-            if (formats == null) {
-                return false;
-            }
-            for (AudioFormat supported : formats) {
-                if (format.matches(supported)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public int getMinBufferSize() {
-            return minBufferSize;
-        }
-
-        public int getMaxBufferSize() {
-            return maxBufferSize;
-        }
-
-        @Override
-        public boolean matches(Line.Info info) {
-            
-            if (!super.matches(info)) {
-                return false;
-            }
-            
-            DataLine.Info inf = (DataLine.Info)info;
-            if ((minBufferSize != AudioSystem.NOT_SPECIFIED
-                    && inf.getMinBufferSize() != AudioSystem.NOT_SPECIFIED 
-                    && minBufferSize < inf.getMinBufferSize())
-                    || (maxBufferSize != AudioSystem.NOT_SPECIFIED
-                            && inf.getMaxBufferSize() != AudioSystem.NOT_SPECIFIED
-                            && maxBufferSize > inf.getMaxBufferSize())) {
-                return false;
-            }
-            
-            for (AudioFormat supported : formats) {
-                if (!inf.isFormatSupported(supported)) {
-                    return false;
-                }
-            }
-
-            return true;
-        }
-        
-        @Override
-        public String toString() {
-            String formatStr = (formats.length == 1? "format " + formats[0].toString() //$NON-NLS-1$
-                    : formats.length + " audio formats"); //$NON-NLS-1$
-            String bufStr = ""; //$NON-NLS-1$
-            if (minBufferSize != AudioSystem.NOT_SPECIFIED) {
-                bufStr = "and buffers of " + minBufferSize + //$NON-NLS-1$
-                    " to " + maxBufferSize + " bytes"; //$NON-NLS-1$ //$NON-NLS-2$
-            }
-            return getLineClass() + " supporting " + formatStr + ", " + bufStr; //$NON-NLS-1$
-        }
-    }
-
-    int available();
-
-    void drain();
-
-    void flush();
-    
-    int getBufferSize();
-    
-    AudioFormat getFormat();
-    
-    int getFramePosition();
-    
-    float getLevel();
-    
-    long getLongFramePosition();
-    
-    long getMicrosecondPosition();
-    
-    boolean isActive();
-    
-    boolean isRunning();
-    
-    void start();
-    
-    void stop();
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/EnumControl.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/EnumControl.java
deleted file mode 100644
index a21a4cc..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/EnumControl.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public abstract class EnumControl extends Control {
-    public static class Type extends Control.Type {
-        public static final Type REVERB = new Type("Reverb"); //$NON-NLS-1$
-
-        protected Type(String name) {
-            super(name);
-        }
-    }
-
-    private Object[] values;
-
-    private Object value;
-
-    protected EnumControl(EnumControl.Type type, Object[] values, Object value) {
-        super(type);
-        this.value = value;
-        this.values = values;
-    }
-
-    public void setValue(Object value) {
-        for (Object val : values) {
-            if (val.equals(value)) {
-                this.value = value;
-                return;
-            }
-        }
-        // sound.0D=The value is not supported
-        throw new IllegalArgumentException(Messages.getString("sound.0D")); //$NON-NLS-1$
-    }
-
-    public Object getValue() {
-        return value;
-    }
-
-    public Object[] getValues() {
-        return values;
-    }
-
-    public String toString() {
-        return getType() + " with current value: " + value; //$NON-NLS-1$
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/FloatControl.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/FloatControl.java
deleted file mode 100644
index 6bf92be..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/FloatControl.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public abstract class FloatControl extends Control {
-
-    public static class Type extends Control.Type {
-        public static final Type MASTER_GAIN = new Type("Master Gain"); //$NON-NLS-1$
-
-        public static final Type AUX_SEND = new Type("AUX Send"); //$NON-NLS-1$
-
-        public static final Type AUX_RETURN = new Type("AUX Return"); //$NON-NLS-1$
-
-        public static final Type REVERB_SEND = new Type("Reverb Send"); //$NON-NLS-1$
-
-        public static final Type REVERB_RETURN = new Type("Reverb Return"); //$NON-NLS-1$
-
-        public static final Type VOLUME = new Type("Volume"); //$NON-NLS-1$
-
-        public static final Type PAN = new Type("Pan"); //$NON-NLS-1$
-
-        public static final Type BALANCE = new Type("Balance"); //$NON-NLS-1$
-
-        public static final Type SAMPLE_RATE = new Type("Sample Rate"); //$NON-NLS-1$
-
-        protected Type(String name) {
-            super(name);
-        }
-    }
-
-    private float value;
-
-    private float maximum;
-
-    private float minimum;
-
-    private String units;
-
-    private String minLabel;
-
-    private String midLabel;
-
-    private String maxLabel;
-
-    private float precision;
-
-    private int updatePeriod;
-
-    protected FloatControl(FloatControl.Type type, float minimum,
-            float maximum, float precision, int updatePeriod,
-            float initialValue, String units, String minLabel, String midLabel,
-            String maxLabel) {
-        super(type);
-        this.maximum = maximum;
-        this.maxLabel = maxLabel;
-        this.midLabel = midLabel;
-        this.minLabel = minLabel;
-        this.minimum = minimum;
-        this.precision = precision;
-        this.units = units;
-        this.updatePeriod = updatePeriod;
-        this.value = initialValue;
-    }
-
-    protected FloatControl(FloatControl.Type type, float minimum,
-            float maximum, float precision, int updatePeriod,
-            float initialValue, String units) {
-        this(type, minimum, maximum, precision, updatePeriod, initialValue,
-                units, "", "", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-    }
-
-    public void setValue(float newValue) {
-        if (newValue > maximum || newValue < minimum) {
-            // sound.0F=value does not fall within the allowable range
-            throw new IllegalArgumentException(Messages.getString("sound.0F")); //$NON-NLS-1$
-        }
-        this.value = newValue;
-    }
-
-    public float getValue() {
-        return this.value;
-    }
-
-    public float getMaximum() {
-        return this.maximum;
-    }
-
-    public float getMinimum() {
-        return this.minimum;
-    }
-
-    public String getUnits() {
-        return this.units;
-    }
-
-    public String getMinLabel() {
-        return this.minLabel;
-    }
-
-    public String getMidLabel() {
-        return this.midLabel;
-    }
-
-    public String getMaxLabel() {
-        return this.maxLabel;
-    }
-
-    public float getPrecision() {
-        return this.precision;
-    }
-
-    public int getUpdatePeriod() {
-        return this.updatePeriod;
-    }
-
-    public void shift(float from, float to, int microseconds) {
-        setValue(to);
-    }
-
-    public String toString() {
-        return getType() + " with current value: "+ value + " " + units  //$NON-NLS-1$ //$NON-NLS-2$
-            + " (range: " + minimum + " - " + maximum + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
-    }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Line.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/Line.java
deleted file mode 100644
index decc68d..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Line.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public interface Line {
-
-    class Info {
-        private Class <?> lineClass;
-        
-        public Info(Class <?> lineClass) {
-            this.lineClass = lineClass;
-        }
-
-        public Class <?> getLineClass( ){
-            return lineClass;
-        }
-
-        public boolean matches(Line.Info info) {
-            return lineClass.isAssignableFrom(info.getLineClass());
-        }
-        
-        @Override
-        public String toString() {
-            return lineClass.toString();
-        }
-    }
-
-    void addLineListener(LineListener listener);
-
-    void close();
-
-    Control getControl(Control.Type control);
-
-    Control[] getControls();
-
-    Line.Info getLineInfo();
-
-    boolean isControlSupported(Control.Type control);
-
-    boolean isOpen();
-
-    void open() throws LineUnavailableException;
-
-    void removeLineListener(LineListener listener);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineEvent.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineEvent.java
deleted file mode 100644
index 95a480a..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineEvent.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.util.EventObject;
-
-public class LineEvent extends EventObject {
-
-    /**
-     * 
-     */
-    private static final long serialVersionUID = -1274246333383880410L;
-    
-    private LineEvent.Type type;
-    private long position;
-
-    public static class Type {
-
-        public static final Type CLOSE = new Type("Close"); //$NON-NLS-1$
-
-        public static final Type OPEN = new Type("Open"); //$NON-NLS-1$
-
-        public static final Type START = new Type("Start"); //$NON-NLS-1$
-
-        public static final Type STOP = new Type("Stop"); //$NON-NLS-1$
-
-        private String name;
-
-        public Type(String name) {
-            this.name = name;
-        }
-
-        @Override
-        public boolean equals(Object another) {
-            if (this == another) {
-                return true;
-            }
-
-            if (another == null || !(another instanceof Type)) {
-                return false;
-            }
-
-            Type obj = (Type) another;
-            return name == null ? obj.name == null : name.equals(obj.name);
-        }
-
-        @Override
-        public final int hashCode() {
-            return name == null ? 0 : name.hashCode();
-        }
-
-        @Override
-        public String toString() {
-            return name;
-        }
-    }
-
-    public LineEvent(Line line, LineEvent.Type type, long position) {
-        super(line);
-        this.type = type;
-        this.position = position;
-    }
-    
-    public final Line getLine() {
-        return (Line)getSource();
-    }
-    
-    public final LineEvent.Type getType() {
-        return type;
-    }
-    
-    public final long getFramePosition() {
-        return position;
-    }
-    
-    public String toString() {
-        return type + " event from line " + getLine(); //$NON-NLS-1$
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineListener.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineListener.java
deleted file mode 100644
index a3a828f..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineListener.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-import java.util.EventListener;
-
-public interface LineListener extends EventListener {
-    void update(LineEvent event);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineUnavailableException.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineUnavailableException.java
deleted file mode 100644
index 5a687ed..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/LineUnavailableException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public class LineUnavailableException extends Exception {
-    private static final long serialVersionUID = -2046718279487432130L;
-
-    public LineUnavailableException() {
-        super();
-    }
-
-    public LineUnavailableException(String message) {
-        super(message);
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Mixer.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/Mixer.java
deleted file mode 100644
index f9fefda..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Mixer.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public interface Mixer extends Line {
-
-    public static class Info {
-        private String name;
-        private String vendor;
-        private String description;
-        private String version;        
-        
-        protected Info(String name, String vendor, String description, String version) {
-            this.name = name;
-            this.vendor = vendor;
-            this.description = description;
-            this.version = version;
-        }
-        
-        @Override
-        public final boolean equals(Object another) {
-            return this == another;
-        }
-        
-        public final String getDescription() {
-            return description;
-        }
-        
-        public final String getName() {
-            return name;
-        }
-        
-        public final String getVendor() {
-            return vendor;
-        }
-        
-        public final String getVersion() {
-            return version;
-        }
-        
-        @Override
-        public final int hashCode() {
-            return name.hashCode() + vendor.hashCode() + description.hashCode() + version.hashCode();
-        }
-        
-        @Override
-        public final String toString() {
-            return name + ", version " + version; //$NON-NLS-1$
-        }
-    }
-
-    Line getLine(Line.Info info) throws LineUnavailableException;
-    
-    int getMaxLines(Line.Info info);
-    
-    Mixer.Info getMixerInfo();
-    
-    Line.Info[] getSourceLineInfo();
-    
-    Line.Info[] getSourceLineInfo(Line.Info info);
-    
-    Line[] getSourceLines();
-    
-    Line.Info[] getTargetLineInfo();
-    
-    Line.Info[] getTargetLineInfo(Line.Info info);
-    
-    Line[] getTargetLines();
-    
-    boolean isLineSupported(Line.Info info);
-    
-    boolean isSynchronizationSupported(Line[] lines, boolean maintainSync);
-    
-    void synchronize(Line[] lines, boolean maintainSync);
-
-    void unsynchronize(Line[] lines);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Port.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/Port.java
deleted file mode 100644
index 68d0638..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/Port.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public interface Port extends Line {
-
-    public static class Info extends Line.Info {
-
-        private String name;
-
-        private boolean isSource;
-
-        public static final Info MICROPHONE = new Info(Port.class,
-                "MICROPHONE", true); //$NON-NLS-1$
-
-        public static final Info LINE_IN = new Info(Port.class, "LINE_IN", true); //$NON-NLS-1$
-
-        public static final Info COMPACT_DISC = new Info(Port.class,
-                "COMPACT_DISC", true); //$NON-NLS-1$
-
-        public static final Info SPEAKER = new Info(Port.class, "SPEAKER", //$NON-NLS-1$
-                false);
-
-        public static final Info HEADPHONE = new Info(Port.class, "HEADPHONES", //$NON-NLS-1$
-                false);
-
-        public static final Info LINE_OUT = new Info(Port.class, "LINE_OUT", //$NON-NLS-1$
-                false);
-
-        public Info(Class<?> lineClass, String name, boolean isSource) {
-            super(lineClass);
-            this.name = name;
-            this.isSource = isSource;
-        }
-
-        public String getName() {
-            return this.name;
-        }
-
-        public boolean isSource() {
-            return this.isSource;
-        }
-
-        public boolean matches(Line.Info info) {
-            if (super.matches(info) && Port.Info.class.equals(info.getClass())
-                    && name.equals(((Port.Info) info).getName())
-                    && isSource == ((Port.Info) info).isSource()) {
-                return true;
-            }
-            return false;
-        }
-
-        public final boolean equals(Object obj) {
-            return this == obj;
-        }
-
-        public final int hashCode() {
-            return name.hashCode() ^ getLineClass().hashCode();
-        }
-
-        public final String toString() {
-            return name + (isSource ? " source port" : " target port"); //$NON-NLS-1$ //$NON-NLS-2$
-        }
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/ReverbType.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/ReverbType.java
deleted file mode 100644
index 9645ba6..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/ReverbType.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public class ReverbType {
-
-    protected ReverbType(String name, int earlyReflectionDelay,
-            float earlyReflectionIntensity, int lateReflectionDelay,
-            float lateReflectionIntensity, int decayTime) {
-        this.name = name;
-        this.earlyReflectionDelay = earlyReflectionDelay;
-        this.earlyReflectionIntensity = earlyReflectionIntensity;
-        this.lateReflectionDelay = lateReflectionDelay;
-        this.lateReflectionIntensity = lateReflectionIntensity;
-        this.decayTime = decayTime;
-    }
-
-    private String name;
-
-    private int earlyReflectionDelay;
-
-    private float earlyReflectionIntensity;
-
-    private int lateReflectionDelay;
-
-    private float lateReflectionIntensity;
-
-    private int decayTime;
-
-    public String getName() {
-        return this.name;
-    }
-
-    public final int getEarlyReflectionDelay() {
-        return this.earlyReflectionDelay;
-    }
-
-    public final float getEarlyReflectionIntensity() {
-        return this.earlyReflectionIntensity;
-    }
-
-    public final int getLateReflectionDelay() {
-        return this.lateReflectionDelay;
-    }
-
-    public final float getLateReflectionIntensity() {
-        return this.lateReflectionIntensity;
-    }
-
-    public final int getDecayTime() {
-        return this.decayTime;
-    }
-
-    public final boolean equals(Object obj) {
-        return this == obj;
-    }
-
-    public final int hashCode() {
-        return toString().hashCode();
-    }
-
-    public final String toString() {
-        return name + ", early reflection delay " + earlyReflectionDelay //$NON-NLS-1$
-                + " ns, early reflection intensity " + earlyReflectionIntensity //$NON-NLS-1$
-                + " dB, late deflection delay " + lateReflectionDelay //$NON-NLS-1$
-                + " ns, late reflection intensity " + lateReflectionIntensity //$NON-NLS-1$
-                + " dB, decay time " + decayTime; //$NON-NLS-1$
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/SourceDataLine.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/SourceDataLine.java
deleted file mode 100644
index 4d68221..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/SourceDataLine.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public interface SourceDataLine extends DataLine {
-    
-    void open(AudioFormat format) throws LineUnavailableException;
-
-    void open(AudioFormat format, int bufferSize)
-            throws LineUnavailableException;
-
-    int write(byte[] b, int off, int len);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/TargetDataLine.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/TargetDataLine.java
deleted file mode 100644
index f4c37c8..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/TargetDataLine.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public interface TargetDataLine extends DataLine {
-
-    void open(AudioFormat format) throws LineUnavailableException;
-
-    void open(AudioFormat format, int bufferSize)
-            throws LineUnavailableException;
-
-    int read(byte[] b, int off, int len);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/UnsupportedAudioFileException.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/UnsupportedAudioFileException.java
deleted file mode 100644
index 590266f..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/UnsupportedAudioFileException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled;
-
-public class UnsupportedAudioFileException extends Exception {
-    private static final long serialVersionUID = -139127412623160368L;
-
-    public UnsupportedAudioFileException() {
-        super();
-    }
-
-    public UnsupportedAudioFileException(String message) {
-        super(message);
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/AudioFileReader.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/AudioFileReader.java
deleted file mode 100644
index 5c01df5..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/AudioFileReader.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled.spi;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import javax.sound.sampled.AudioFileFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.UnsupportedAudioFileException;
-
-public abstract class AudioFileReader {
-
-    public abstract AudioFileFormat getAudioFileFormat(File file)
-            throws UnsupportedAudioFileException, IOException;
-
-    public abstract AudioFileFormat getAudioFileFormat(InputStream stream)
-            throws UnsupportedAudioFileException, IOException;
-
-    public abstract AudioFileFormat getAudioFileFormat(URL url)
-            throws UnsupportedAudioFileException, IOException;
-
-    public abstract AudioInputStream getAudioInputStream(File file)
-            throws UnsupportedAudioFileException, IOException;
-
-    public abstract AudioInputStream getAudioInputStream(InputStream stream)
-            throws UnsupportedAudioFileException, IOException;
-
-    public abstract AudioInputStream getAudioInputStream(URL url)
-            throws UnsupportedAudioFileException, IOException;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/AudioFileWriter.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/AudioFileWriter.java
deleted file mode 100644
index 0bae3f3..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/AudioFileWriter.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled.spi;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.AudioFileFormat;
-import javax.sound.sampled.AudioFileFormat.Type;
-
-public abstract class AudioFileWriter {
-
-    public abstract AudioFileFormat.Type[] getAudioFileTypes();
-
-    public abstract AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream);
-
-    public boolean isFileTypeSupported(AudioFileFormat.Type fileType) {
-        AudioFileFormat.Type[] supported = getAudioFileTypes();
-        for (Type element : supported) {
-            if (fileType.equals(element)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public boolean isFileTypeSupported(AudioFileFormat.Type fileType, AudioInputStream stream) {
-        AudioFileFormat.Type[] supported = getAudioFileTypes(stream);
-        for (Type element : supported) {
-            if (fileType.equals(element)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public abstract int write(AudioInputStream stream,
-            AudioFileFormat.Type fileType, File out) throws IOException;
-
-    public abstract int write(AudioInputStream stream,
-            AudioFileFormat.Type fileType, OutputStream out) throws IOException;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/FormatConversionProvider.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/FormatConversionProvider.java
deleted file mode 100644
index ed0d69f..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/FormatConversionProvider.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled.spi;
-
-import javax.sound.sampled.AudioFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.AudioFormat.Encoding;
-
-public abstract class FormatConversionProvider {
-
-    public abstract AudioInputStream getAudioInputStream(
-            AudioFormat.Encoding targetEncoding, AudioInputStream sourceStream);
-
-    public abstract AudioInputStream getAudioInputStream(
-            AudioFormat targetFormat, AudioInputStream sourceStream);
-
-    public abstract AudioFormat.Encoding[] getTargetEncodings(
-            AudioFormat sourceFormat);
-
-    public boolean isConversionSupported(AudioFormat.Encoding targetEncoding,
-            AudioFormat sourceFormat) {
-        AudioFormat.Encoding[] encodings = getTargetEncodings(sourceFormat);
-        for (Encoding element : encodings) {
-            if (targetEncoding.equals(element)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public abstract AudioFormat[] getTargetFormats(
-            AudioFormat.Encoding targetFormat, AudioFormat sourceFormat);
-
-    public boolean isConversionSupported(AudioFormat targetFormat,
-            AudioFormat sourceFormat) {
-        AudioFormat[] formats = getTargetFormats(targetFormat.getEncoding(),
-                sourceFormat);
-        for (AudioFormat element : formats) {
-            if (targetFormat.equals(element)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public abstract AudioFormat.Encoding[] getSourceEncodings();
-
-    public boolean isSourceEncodingSupported(AudioFormat.Encoding sourceEncoding) {
-        AudioFormat.Encoding[] encodings = getSourceEncodings();
-        for (Encoding element : encodings) {
-            if (sourceEncoding.equals(element)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public abstract AudioFormat.Encoding[] getTargetEncodings();
-
-    public boolean isTargetEncodingSupported(AudioFormat.Encoding targetEncoding) {
-        AudioFormat.Encoding[] encodings = getTargetEncodings();
-        for (Encoding element : encodings) {
-            if (targetEncoding.equals(element)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/MixerProvider.java b/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/MixerProvider.java
deleted file mode 100644
index 86fdbb7..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/sampled/spi/MixerProvider.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package javax.sound.sampled.spi;
-
-import javax.sound.sampled.Mixer;
-import javax.sound.sampled.Mixer.Info;
-
-public abstract class MixerProvider {
-
-    public abstract Mixer getMixer(Mixer.Info info);
-
-    public abstract Mixer.Info[] getMixerInfo();
-
-    public boolean isMixerSupported(Mixer.Info info) {
-        Mixer.Info[] devices = getMixerInfo();
-        for (Info element : devices) {
-            if (info.equals(element)) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/internal/nls/Messages.java b/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/internal/nls/Messages.java
deleted file mode 100644
index 65ecb83..0000000
--- a/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/internal/nls/Messages.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/* 
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
- * All changes made to this file manually will be overwritten 
- * if this tool runs again. Better make changes in the template file.
- */
-
-package org.apache.harmony.sound.internal.nls;
-
-import org.apache.harmony.luni.util.MsgHelp;
-
-/**
- * This class retrieves strings from a resource bundle and returns them,
- * formatting them with MessageFormat when required.
- * <p>
- * It is used by the system classes to provide national language support, by
- * looking up messages in the <code>
- *    org.apache.harmony.sound.internal.nls.messages
- * </code>
- * resource bundle. Note that if this file is not available, or an invalid key
- * is looked up, or resource bundle support is not available, the key itself
- * will be returned as the associated message. This means that the <em>KEY</em>
- * should a reasonable human-readable (english) string.
- * 
- */
-public class Messages {
-
-    private static final String sResource =
-        "org.apache.harmony.sound.internal.nls.messages"; //$NON-NLS-1$
-
-    /**
-     * Retrieves a message which has no arguments.
-     * 
-     * @param msg
-     *            String the key to look up.
-     * @return String the message for that key in the system message bundle.
-     */
-    static public String getString(String msg) {
-        return MsgHelp.getString(sResource, msg);
-    }
-
-    /**
-     * Retrieves a message which takes 1 argument.
-     * 
-     * @param msg
-     *            String the key to look up.
-     * @param arg
-     *            Object the object to insert in the formatted output.
-     * @return String the message for that key in the system message bundle.
-     */
-    static public String getString(String msg, Object arg) {
-        return getString(msg, new Object[] { arg });
-    }
-
-    /**
-     * Retrieves a message which takes 1 integer argument.
-     * 
-     * @param msg
-     *            String the key to look up.
-     * @param arg
-     *            int the integer to insert in the formatted output.
-     * @return String the message for that key in the system message bundle.
-     */
-    static public String getString(String msg, int arg) {
-        return getString(msg, new Object[] { Integer.toString(arg) });
-    }
-
-    /**
-     * Retrieves a message which takes 1 character argument.
-     * 
-     * @param msg
-     *            String the key to look up.
-     * @param arg
-     *            char the character to insert in the formatted output.
-     * @return String the message for that key in the system message bundle.
-     */
-    static public String getString(String msg, char arg) {
-        return getString(msg, new Object[] { String.valueOf(arg) });
-    }
-
-    /**
-     * Retrieves a message which takes 2 arguments.
-     * 
-     * @param msg
-     *            String the key to look up.
-     * @param arg1
-     *            Object an object to insert in the formatted output.
-     * @param arg2
-     *            Object another object to insert in the formatted output.
-     * @return String the message for that key in the system message bundle.
-     */
-    static public String getString(String msg, Object arg1, Object arg2) {
-        return getString(msg, new Object[] { arg1, arg2 });
-    }
-
-    /**
-     * Retrieves a message which takes several arguments.
-     * 
-     * @param msg
-     *            String the key to look up.
-     * @param args
-     *            Object[] the objects to insert in the formatted output.
-     * @return String the message for that key in the system message bundle.
-     */
-    static public String getString(String msg, Object[] args) {
-        return MsgHelp.getString(sResource, msg, args);
-    }
-}
diff --git a/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/internal/nls/messages.properties b/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/internal/nls/messages.properties
deleted file mode 100644
index efcf80b..0000000
--- a/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/internal/nls/messages.properties
+++ /dev/null
@@ -1,39 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#  
-#      http://www.apache.org/licenses/LICENSE-2.0
-#  
-#  Unless required by applicable law or agreed to in writing, software
-#  distributed under the License is distributed on an "AS IS" BASIS,
-#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#  See the License for the specific language governing permissions and
-#  limitations under the License.
-# 
-
-# messages for EN locale
-sound.01=-1
-sound.02=Index: {0}, Size: {1}
-sound.03=length out of bounds: {0}
-sound.04=Invalid status byte: {0}
-sound.05=command out of range: {0}
-sound.06=channel out of range: {0}
-sound.07=data1 out of range: {0}
-sound.08=data2 out of range: {0}
-sound.09=Invalid status byte for sysex message: {0}
-sound.0A=Invalid meta event with type {0}
-sound.0B=Unsupported division type: {0}
-sound.0C=Frame size must be one byte
-sound.0D=The value is not supported
-sound.0F=value does not fall within the allowable range
-sound.11=Could not get line
-sound.12=Could not get audio input stream from source stream
-sound.13=Could not get audio input stream from source stream
-sound.14=File is not a supported file type
-sound.15=Could not get audio input stream from input stream
-sound.16=Could not get audio input stream from input URL
-sound.17=Could not get audio input stream from input file
-sound.18=Type is not supported
diff --git a/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/utils/ProviderService.java b/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/utils/ProviderService.java
deleted file mode 100644
index b1bbe2e..0000000
--- a/libcore-disabled/sound/src/main/java/org/apache/harmony/sound/utils/ProviderService.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-package org.apache.harmony.sound.utils;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.URL;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Properties;
-
-public class ProviderService {
-
-    // Properties from sound.propertie file
-    private static Properties devices;
-
-    static {
-        devices = new Properties();
-
-        FileInputStream fstream = AccessController
-                .doPrivileged(new PrivilegedAction<FileInputStream>() {
-
-                    public FileInputStream run() {
-                        // obtain the path to the file sound.properties
-                        String soundPropertiesPath = System
-                                .getProperty("java.home") //$NON-NLS-1$
-                                + File.separator + "lib" + File.separator //$NON-NLS-1$
-                                + "sound.properties"; //$NON-NLS-1$
-                        try {
-                            return new FileInputStream(soundPropertiesPath);
-                        } catch (FileNotFoundException e) {
-                            return null;
-                        }
-                    }
-                });
-
-        if (fstream != null) {
-            // reading file sound.properties
-            try {
-                devices.load(fstream);
-            } catch (IOException e) {}
-        }
-    }
-
-    /**
-     * this method return information about default device
-     * 
-     * @param deviceName
-     * @return
-     */
-    public static List<String> getDefaultDeviceDescription(String deviceName) {
-
-        // variable that contain information about default device
-        List<String> defaultDevice = new ArrayList<String>();
-        String str;
-        int index;
-
-        /*
-         * obtain the default device that describes by deviceName
-         */
-        str = devices.getProperty(deviceName);
-        /*
-         * if default device doesn't define, than return empty defaultDevice
-         */
-        if (str == null) {
-            return defaultDevice;
-        }
-        /*
-         * the separator between provider and name is '#'; find separator of
-         * provider and name of device in the notation of default device
-         */
-        index = str.indexOf("#"); //$NON-NLS-1$
-        /*
-         * if separator doesn't find, so in the definition of default device
-         * contain only name of provider, and so we add it
-         */
-        if (index == -1) {
-            defaultDevice.add(str);
-            defaultDevice.add(null);
-            /*
-             * if separator is the first symbol, so definition contain only name
-             * of device
-             */
-        } else if (index == 0) {
-            defaultDevice.add(null);
-            defaultDevice.add(str.substring(index + 1));
-            /*
-             * if separator is not the first, so we find provider and name of
-             * device
-             */
-        } else {
-            defaultDevice.add(str.substring(0, index));
-            defaultDevice.add(str.substring(index + 1));
-        }
-        return defaultDevice;
-    }
-
-    /**
-     * this method return the list of providers
-     * 
-     * @param providerName
-     * @return
-     */
-    public static List<?> getProviders(String providerName) {
-        final String name = providerName;
-
-        return AccessController
-                .doPrivileged(new PrivilegedAction<List<Object>>() {
-
-                    public List<Object> run() {
-                        List<Object> providers = new ArrayList<Object>();
-                        String className = null;
-                        byte[] bytes;
-
-                        ClassLoader cl = ClassLoader.getSystemClassLoader();
-                        Enumeration<URL> urls = null;
-                        try {
-                            urls = cl.getResources(name);
-                        } catch (IOException e) {
-                            return providers;
-                        }
-                        for (; urls.hasMoreElements();) {
-                            try {
-                                InputStream in = urls.nextElement()
-                                        .openStream();
-                                bytes = new byte[in.available()];
-                                in.read(bytes);
-                                in.close();
-                            } catch (IOException e) {
-                                continue;
-                            }
-                            String[] astr = new String(bytes).split("\r\n"); //$NON-NLS-1$
-                            for (String str : astr) {
-                                className = str.trim();
-                                if (!className.startsWith("#")) { // skip
-                                                                    // comments
-                                                                    // //$NON-NLS-1$
-                                    try {
-                                        providers.add(Class.forName(
-                                                className.trim(), true, cl)
-                                                .newInstance());
-                                    } catch (IllegalAccessException e) {} catch (InstantiationException e) {} catch (ClassNotFoundException e) {}
-                                }
-                            }
-                        }
-                        return providers;
-                    }
-                });
-
-    }
-
-    public static Properties getSoundProperties() {
-        return devices;
-    }
-
-}
diff --git a/libcore-disabled/sound/src/test/java/android/core/SoundTest.java b/libcore-disabled/sound/src/test/java/android/core/SoundTest.java
deleted file mode 100644
index 22a9261..0000000
--- a/libcore-disabled/sound/src/test/java/android/core/SoundTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.core;
-
-import android.media.MediaPlayer;
-
-import com.android.internal.sound.midi.AndroidSequencer;
-import com.android.internal.sound.sampled.AndroidClip;
-
-import junit.framework.Assert;
-import junit.framework.TestCase;
-
-import java.io.File;
-
-import javax.sound.midi.MidiDevice;
-import javax.sound.midi.MidiSystem;
-import javax.sound.midi.Sequence;
-import javax.sound.midi.Sequencer;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.AudioSystem;
-import javax.sound.sampled.Clip;
-import javax.sound.sampled.Line;
-
-public class SoundTest extends TestCase {
-
-  public static String TAG = "SoundTest";
-
-    // Regression test for #000000: Completion of MIDI file doesn't fire
-    // corresponding event.
-//    private boolean eventReceived = false;
-//  
-//    public void testMidiFileCompletion() {
-//        try {
-//            MediaPlayer player = new MediaPlayer();
-//            
-//            player.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
-//                public void onCompletion(MediaPlayer player) {
-//                    eventReceived = true;
-//                }
-//            });
-//
-//            player.setDataSource("/system/sounds/test.mid");
-//            player.prepare();
-//            player.start();
-//            Thread.sleep(20000);
-//            assertFalse("Player must be stopped", player.isPlaying());
-//            assertTrue("Completion event must have been received", eventReceived);
-//
-//        } catch (Exception ex) {
-//            throw new RuntimeException(ex);
-//        }
-//    }
-  
-    // Regression test for #872614: General javax.sound weirdness.
-    public void testMidiSupport() {
-        try {
-            Sequencer sequencer = MidiSystem.getSequencer();
-            Assert.assertTrue("AndroidSequencer must exist", sequencer instanceof AndroidSequencer);
-            
-            MidiDevice.Info info = sequencer.getDeviceInfo();
-            Assert.assertNotNull("Device info must exist", info);
-    
-            Sequence sequence = MidiSystem.getSequence(new File("/system/sounds/test.mid"));
-            Assert.assertNotNull("Sequence must exist", sequence);
-    
-            Assert.assertFalse("Sequencer must not be open", sequencer.isOpen());
-            sequencer.open();
-            Assert.assertTrue("Sequencer must be open", sequencer.isOpen());
-            
-            Assert.assertNull("Sequencer must not have Sequence", sequencer.getSequence());
-            sequencer.setSequence(sequence);
-            Assert.assertNotNull("Sequencer must have Sequence", sequencer.getSequence());
-            
-            Assert.assertFalse("Sequencer must not be running", sequencer.isRunning());
-            sequencer.start();
-            Thread.sleep(1000);
-            Assert.assertTrue("Sequencer must be running (after 1 second)", sequencer.isRunning());
-    
-            Thread.sleep(3000);
-            
-            Assert.assertTrue("Sequencer must be running", sequencer.isRunning());
-            sequencer.stop();
-            Thread.sleep(1000);
-            Assert.assertFalse("Sequencer must not be running (after 1 second)", sequencer.isRunning());
-            
-            sequencer.close();
-            Assert.assertFalse("Sequencer must not be open", sequencer.isOpen());
-        } catch (Exception ex) {
-            throw new RuntimeException(ex);
-        }
-    } 
-
-    // Regression test for #872614: General javax.sound weirdness.
-    public void testSampledSupport() {
-        try {
-            Clip clip = AudioSystem.getClip();
-            Assert.assertTrue("AndroidClip must exist", clip instanceof AndroidClip);
-            
-            Line.Info info = clip.getLineInfo();
-            Assert.assertNotNull("Line info must exist", info);
-    
-            AudioInputStream stream = AudioSystem.getAudioInputStream(new File("/system/media/audio/ringtones/ringer.ogg"));
-            Assert.assertNotNull("AudioInputStream must exist", stream);
-    
-            Assert.assertFalse("Clip must not be open", clip.isOpen());
-            clip.open(stream);
-            Assert.assertTrue("Clip must be open", clip.isOpen());
-            
-            Assert.assertFalse("Clip must not be running", clip.isRunning());
-            clip.start();
-            Thread.sleep(1000);
-            Assert.assertTrue("Clip must be running (after 1 second)", clip.isRunning());
-    
-            Thread.sleep(2000);
-            
-            Assert.assertTrue("Clip must be running", clip.isRunning());
-            clip.stop();
-            Thread.sleep(1000);
-            Assert.assertFalse("Clip must not be running (after 1 second)", clip.isRunning());
-            
-            clip.close();
-            Assert.assertFalse("Clip must not be open", clip.isOpen());
-        } catch (Exception ex) {
-            throw new RuntimeException(ex);
-        }
-    } 
-    
-}
diff --git a/libcore/awt-kernel/src/main/java/java/awt/font/TextAttribute.java b/libcore/awt-kernel/src/main/java/java/awt/font/TextAttribute.java
index aa1394a..f887540 100644
--- a/libcore/awt-kernel/src/main/java/java/awt/font/TextAttribute.java
+++ b/libcore/awt-kernel/src/main/java/java/awt/font/TextAttribute.java
@@ -137,13 +137,13 @@
      * The Constant RUN_DIRECTION_LTR indicates left-to-right run 
      * direction. 
      */
-    public static final Boolean RUN_DIRECTION_LTR = new Boolean(false);
+    public static final Boolean RUN_DIRECTION_LTR = false;
 
     /** 
      * The Constant RUN_DIRECTION_RTL indicates right-to-left run
      * direction. 
      */
-    public static final Boolean RUN_DIRECTION_RTL = new Boolean(true);
+    public static final Boolean RUN_DIRECTION_RTL = true;
 
     /** The SIZE text attribute. */
     public static final TextAttribute SIZE = new TextAttribute("size"); //$NON-NLS-1$
@@ -152,16 +152,16 @@
     public static final TextAttribute STRIKETHROUGH = new TextAttribute("strikethrough"); //$NON-NLS-1$
 
     /** The Constant STRIKETHROUGH_ON indicates a single strikethrough. */
-    public static final Boolean STRIKETHROUGH_ON = new Boolean(true);
+    public static final Boolean STRIKETHROUGH_ON = true;
 
     /** The SUPERSCRIPT text attribute. */
     public static final TextAttribute SUPERSCRIPT = new TextAttribute("superscript"); //$NON-NLS-1$
 
     /** The Constant SUPERSCRIPT_SUB indicates a standard subscript. */
-    public static final Integer SUPERSCRIPT_SUB = new Integer(-1);
+    public static final Integer SUPERSCRIPT_SUB = -1;
 
     /** The Constant SUPERSCRIPT_SUPER indicates a standard superscript. */
-    public static final Integer SUPERSCRIPT_SUPER = new Integer(1);
+    public static final Integer SUPERSCRIPT_SUPER = 1;
 
     /** The SWAP_COLORS text attribute. */
     public static final TextAttribute SWAP_COLORS = new TextAttribute("swap_colors"); //$NON-NLS-1$
@@ -170,7 +170,7 @@
      * The Constant SWAP_COLORS_ON indicates a swap of foreground 
      * and background.
      */
-    public static final Boolean SWAP_COLORS_ON = new Boolean(true);
+    public static final Boolean SWAP_COLORS_ON = true;
 
     /** The TRANSFORM text attribute. */
     public static final TextAttribute TRANSFORM = new TextAttribute("transform"); //$NON-NLS-1$
@@ -182,37 +182,37 @@
      * The Constant UNDERLINE_ON indicates a standard underline 
      * at the roman baseline for roman text.
      */
-    public static final Integer UNDERLINE_ON = new Integer(0);
+    public static final Integer UNDERLINE_ON = 0;
 
     /** 
      * The Constant UNDERLINE_LOW_ONE_PIXEL indicates a single 
      * pixel solid low underline. 
      */
-    public static final Integer UNDERLINE_LOW_ONE_PIXEL = new Integer(1);
+    public static final Integer UNDERLINE_LOW_ONE_PIXEL = 1;
 
     /** 
      * The Constant UNDERLINE_LOW_TWO_PIXEL indicates a double 
      * pixel solid low underline. 
      */
-    public static final Integer UNDERLINE_LOW_TWO_PIXEL = new Integer(2);
+    public static final Integer UNDERLINE_LOW_TWO_PIXEL = 2;
 
     /** 
      * The Constant UNDERLINE_LOW_DOTTED indicates a 
      * single pixel dotted low underline. 
      */
-    public static final Integer UNDERLINE_LOW_DOTTED = new Integer(3);
+    public static final Integer UNDERLINE_LOW_DOTTED = 3;
 
     /** 
      * The Constant UNDERLINE_LOW_GRAY indicates double pixel 
      * gray low underline. 
      */
-    public static final Integer UNDERLINE_LOW_GRAY = new Integer(4);
+    public static final Integer UNDERLINE_LOW_GRAY = 4;
 
     /** 
      * The Constant UNDERLINE_LOW_DASHED indicates single pixel dashed 
      * low underline. 
      */
-    public static final Integer UNDERLINE_LOW_DASHED = new Integer(5);
+    public static final Integer UNDERLINE_LOW_DASHED = 5;
 
     /** The WEIGHT text attribute. */
     public static final TextAttribute WEIGHT = new TextAttribute("weight"); //$NON-NLS-1$
diff --git a/libcore/awt-kernel/src/main/java/java/beans/PropertyChangeSupport.java b/libcore/awt-kernel/src/main/java/java/beans/PropertyChangeSupport.java
index 9225d95..32e2da6 100644
--- a/libcore/awt-kernel/src/main/java/java/beans/PropertyChangeSupport.java
+++ b/libcore/awt-kernel/src/main/java/java/beans/PropertyChangeSupport.java
@@ -266,7 +266,7 @@
 
         if (oldValue != newValue) {
             fireIndexedPropertyChange(propertyName, index,
-                    new Integer(oldValue), new Integer(newValue));
+                    Integer.valueOf(oldValue), Integer.valueOf(newValue));
         }
     }
 
diff --git a/libcore/concurrent/src/test/java/tests/api/java/util/concurrent/JSR166TestCase.java b/libcore/concurrent/src/test/java/tests/api/java/util/concurrent/JSR166TestCase.java
index 4e0de95..6acd363 100644
--- a/libcore/concurrent/src/test/java/tests/api/java/util/concurrent/JSR166TestCase.java
+++ b/libcore/concurrent/src/test/java/tests/api/java/util/concurrent/JSR166TestCase.java
@@ -168,7 +168,10 @@
      * be reimplemented to use for example a Property.
      */
     protected long getShortDelay() {
-        return 50;
+        // BEGIN android-changed
+        // original value is 50
+        return 250;
+        // END android-changed
     }
 
 
diff --git a/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java b/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
index 6f64c5f..31e82ec 100644
--- a/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
+++ b/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
@@ -359,6 +359,14 @@
      */
     public static native void crash();
 
+    /**
+     * Together with gdb, provide a handy way to stop the VM at user-tagged
+     * locations.
+     *
+     * @hide
+     */
+    public static native void infopoint(int id);
+
     /*
      * Fake method, inserted into dmtrace output when the garbage collector
      * runs.  Not actually called.
diff --git a/libcore/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java b/libcore/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java
index a7d429a..61bee34 100644
--- a/libcore/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java
+++ b/libcore/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java
@@ -155,7 +155,6 @@
 
                 if (!mRegistrationComplete) {
                     /* timed out, don't wait again */
-                    System.out.println("DDM dispatch reg wait timeout");
                     mRegistrationTimedOut = true;
                 }
             }
@@ -165,8 +164,6 @@
         //System.out.println(" dispatch cont");
 
         if (handler == null) {
-            System.err.println("Can't dispatch DDM chunk "
-                + Integer.toHexString(type) + ": no handler defined");
             return null;
         }
 
diff --git a/libcore/json/src/main/java/org/json/JSON.java b/libcore/json/src/main/java/org/json/JSON.java
new file mode 100644
index 0000000..029884b
--- /dev/null
+++ b/libcore/json/src/main/java/org/json/JSON.java
@@ -0,0 +1,112 @@
+/*
+ * 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 org.json;
+
+class JSON {
+    /**
+     * Returns the input if it is a JSON-permissable value; throws otherwise.
+     */
+    static double checkDouble(double d) throws JSONException {
+        if (Double.isInfinite(d) || Double.isNaN(d)) {
+            throw new JSONException("Forbidden numeric value: " + d);
+        }
+        return d;
+    }
+
+    static Boolean toBoolean(Object value) {
+        if (value instanceof Boolean) {
+            return (Boolean) value;
+        } else if (value instanceof String) {
+            return Boolean.valueOf(((String) value));
+        } else {
+            return null;
+        }
+    }
+
+    static Double toDouble(Object value) {
+        if (value instanceof Double) {
+            return (Double) value;
+        } else if (value instanceof Number) {
+            return ((Number) value).doubleValue();
+        } else if (value instanceof String) {
+            try {
+                return Double.valueOf((String) value);
+            } catch (NumberFormatException e) {
+            }
+        }
+        return null;
+    }
+
+    static Integer toInteger(Object value) {
+        if (value instanceof Integer) {
+            return (Integer) value;
+        } else if (value instanceof Number) {
+            return ((Number) value).intValue();
+        } else if (value instanceof String) {
+            try {
+                return Double.valueOf((String) value).intValue();
+            } catch (NumberFormatException e) {
+            }
+        }
+        return null;
+    }
+
+    static Long toLong(Object value) {
+        if (value instanceof Long) {
+            return (Long) value;
+        } else if (value instanceof Number) {
+            return ((Number) value).longValue();
+        } else if (value instanceof String) {
+            try {
+                return Double.valueOf((String) value).longValue();
+            } catch (NumberFormatException e) {
+            }
+        }
+        return null;
+    }
+
+    static String toString(Object value) {
+        if (value instanceof String) {
+            return (String) value;
+        } else if (value != null) {
+            return String.valueOf(value);
+        }
+        return null;
+    }
+
+    public static JSONException typeMismatch(Object indexOrName, Object actual,
+            String requiredType) throws JSONException {
+        if (actual == null) {
+            throw new JSONException("Value at " + indexOrName + " is null.");
+        } else {
+            throw new JSONException("Value " + actual + " at " + indexOrName
+                    + " of type " + actual.getClass().getName()
+                    + " cannot be converted to " + requiredType);
+        }
+    }
+
+    public static JSONException typeMismatch(Object actual, String requiredType)
+            throws JSONException {
+        if (actual == null) {
+            throw new JSONException("Value is null.");
+        } else {
+            throw new JSONException("Value " + actual
+                    + " of type " + actual.getClass().getName()
+                    + " cannot be converted to " + requiredType);
+        }
+    }
+}
diff --git a/libcore/json/src/main/java/org/json/JSONArray.java b/libcore/json/src/main/java/org/json/JSONArray.java
index 6bfca6e..fa42054 100644
--- a/libcore/json/src/main/java/org/json/JSONArray.java
+++ b/libcore/json/src/main/java/org/json/JSONArray.java
@@ -1,778 +1,322 @@
+/*
+ * 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 org.json;
 
-/*
-Copyright (c) 2002 JSON.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-The Software shall be used for Good, not Evil.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
+import java.util.List;
 import java.util.ArrayList;
 import java.util.Collection;
 
-/**
- * A JSONArray is an ordered sequence of values. Its external text form is a 
- * string wrapped in square brackets with commas separating the values. The 
- * internal form is an object having <code>get</code> and <code>opt</code> 
- * methods for accessing the values by index, and <code>put</code> methods for 
- * adding or replacing values. The values can be any of these types: 
- * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>, 
- * <code>Number</code>, <code>String</code>, or the
- * <code>JSONObject.NULL object</code>.
- * <p>
- * The constructor can convert a JSON text into a Java object. The 
- * <code>toString</code> method converts to JSON text.
- * <p>
- * A <code>get</code> method returns a value if one can be found, and throws an 
- * exception if one cannot be found. An <code>opt</code> method returns a 
- * default value instead of throwing an exception, and so is useful for 
- * obtaining optional values.
- * <p>
- * The generic <code>get()</code> and <code>opt()</code> methods return an 
- * object which you can cast or query for type. There are also typed 
- * <code>get</code> and <code>opt</code> methods that do type checking and type 
- * coersion for you.
- * <p>
- * The texts produced by the <code>toString</code> methods strictly conform to
- * JSON syntax rules. The constructors are more forgiving in the texts they will 
- * accept:
- * <ul>
- * <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just
- *     before the closing bracket.</li>
- * <li>The <code>null</code> value will be inserted when there
- *     is <code>,</code>&nbsp;<small>(comma)</small> elision.</li>
- * <li>Strings may be quoted with <code>'</code>&nbsp;<small>(single
- *     quote)</small>.</li>
- * <li>Strings do not need to be quoted at all if they do not begin with a quote
- *     or single quote, and if they do not contain leading or trailing spaces,
- *     and if they do not contain any of these characters:
- *     <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers
- *     and if they are not the reserved words <code>true</code>,
- *     <code>false</code>, or <code>null</code>.</li>
- * <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as 
- *     well as by <code>,</code> <small>(comma)</small>.</li>
- * <li>Numbers may have the <code>0-</code> <small>(octal)</small> or
- *     <code>0x-</code> <small>(hex)</small> prefix.</li>
- * <li>Comments written in the slashshlash, slashstar, and hash conventions
- *     will be ignored.</li>
- * </ul>
+// Note: this class was written without inspecting the non-free org.json sourcecode.
 
- * @author JSON.org
- * @version 2
+/**
+ * An indexed sequence of JSON-safe values.
  */
 public class JSONArray {
 
+    private final List<Object> values;
 
-    /**
-     * The arrayList where the JSONArray's properties are kept.
-     */
-    private ArrayList myArrayList;
-
-
-    /**
-     * Construct an empty JSONArray.
-     */
     public JSONArray() {
-        this.myArrayList = new ArrayList();
+        values = new ArrayList<Object>();
     }
-    
-    /**
-     * Construct a JSONArray from a JSONTokener.
-     * @param x A JSONTokener
-     * @throws JSONException If there is a syntax error.
-     */
-    public JSONArray(JSONTokener x) throws JSONException {
+
+    /* Accept a raw type for API compatibility */
+    public JSONArray(Collection copyFrom) {
         this();
-        if (x.nextClean() != '[') {
-            throw x.syntaxError("A JSONArray text must start with '['");
-        }
-        if (x.nextClean() == ']') {
-            return;
-        }
-        x.back();
-        for (;;) {
-            if (x.nextClean() == ',') {
-                x.back();
-                this.myArrayList.add(null);
-            } else {
-                x.back();
-                this.myArrayList.add(x.nextValue());
-            }
-            switch (x.nextClean()) {
-            case ';':
-            case ',':
-                if (x.nextClean() == ']') {
-                    this.myArrayList.add(null);
-                    return;
-                }
-                x.back();
-                break;
-            case ']':
-                return;
-            default:
-                throw x.syntaxError("Expected a ',' or ']'");
-            }
+        Collection<?> copyFromTyped = (Collection<?>) copyFrom;
+        values.addAll(copyFromTyped);
+    }
+
+    public JSONArray(JSONTokener readFrom) throws JSONException {
+        /*
+         * Getting the parser to populate this could get tricky. Instead, just
+         * parse to temporary JSONArray and then steal the data from that.
+         */
+        Object object = readFrom.nextValue();
+        if (object instanceof JSONArray) {
+            values = ((JSONArray) object).values;
+        } else {
+            throw JSON.typeMismatch(object, "JSONArray");
         }
     }
 
-
-    public boolean equals(Object object) {
-        if (!(object instanceof JSONArray)) return false;
-        return myArrayList.equals(((JSONArray)object).myArrayList);
+    public JSONArray(String json) throws JSONException {
+        this(new JSONTokener(json));
     }
 
-    
-    /**
-     * Construct a JSONArray from a source sJSON text.
-     * @param string     A string that begins with
-     * <code>[</code>&nbsp;<small>(left bracket)</small>
-     *  and ends with <code>]</code>&nbsp;<small>(right bracket)</small>.
-     *  @throws JSONException If there is a syntax error.
-     */
-    public JSONArray(String string) throws JSONException {
-        this(new JSONTokener(string));
-    }
-
-
-    /**
-     * Construct a JSONArray from a Collection.
-     * @param collection     A Collection.
-     */
-    public JSONArray(Collection collection) {
-        this.myArrayList = new ArrayList(collection);
-    }
-
-
-    /**
-     * Get the object value associated with an index.
-     * @param index
-     *  The index must be between 0 and length() - 1.
-     * @return An object value.
-     * @throws JSONException If there is no value for the index.
-     */
-    public Object get(int index) throws JSONException {
-        Object o = opt(index);
-        if (o == null) {
-            throw new JSONException("JSONArray[" + index + "] not found.");
-        }
-        return o;
-    }
-
-
-    /**
-     * Get the boolean value associated with an index.
-     * The string values "true" and "false" are converted to boolean.
-     * 
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The truth.
-     * @throws JSONException If there is no value for the index or if the
-     *  value is not convertable to boolean.
-     */
-    public boolean getBoolean(int index) throws JSONException {
-        Object o = get(index);
-        if (o.equals(Boolean.FALSE) ||
-                (o instanceof String &&
-                ((String)o).equalsIgnoreCase("false"))) {
-            return false;
-        } else if (o.equals(Boolean.TRUE) ||
-                (o instanceof String &&
-                ((String)o).equalsIgnoreCase("true"))) {
-            return true;
-        }
-        throw new JSONException("JSONArray[" + index + "] is not a Boolean.");
-    }
-
-
-    /**
-     * Get the double value associated with an index.
-     * 
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The value.
-     * @throws   JSONException If the key is not found or if the value cannot 
-     *  be converted to a number.
-     */
-    public double getDouble(int index) throws JSONException {
-        Object o = get(index);
-        try {
-            return o instanceof Number ? 
-                    ((Number)o).doubleValue() : Double.parseDouble((String)o);
-        } catch (Exception e) {
-            throw new JSONException("JSONArray[" + index + 
-                "] is not a number.");
-        }
-    }
-
-
-    /**
-     * Get the int value associated with an index.
-     * 
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The value.
-     * @throws   JSONException If the key is not found or if the value cannot 
-     *  be converted to a number.
-     *  if the value cannot be converted to a number.
-     */
-    public int getInt(int index) throws JSONException {
-        Object o = get(index);
-        return o instanceof Number ? 
-                ((Number)o).intValue() : (int)getDouble(index);
-    }
-
-
-    /**
-     * Get the JSONArray associated with an index.
-     * @param index The index must be between 0 and length() - 1.
-     * @return      A JSONArray value.
-     * @throws JSONException If there is no value for the index. or if the
-     * value is not a JSONArray
-     */
-    public JSONArray getJSONArray(int index) throws JSONException {
-        Object o = get(index);
-        if (o instanceof JSONArray) {
-            return (JSONArray)o;
-        }
-        throw new JSONException("JSONArray[" + index +
-                "] is not a JSONArray.");
-    }
-
-
-    /**
-     * Get the JSONObject associated with an index.
-     * @param index subscript
-     * @return      A JSONObject value.
-     * @throws JSONException If there is no value for the index or if the
-     * value is not a JSONObject
-     */
-    public JSONObject getJSONObject(int index) throws JSONException {
-        Object o = get(index);
-        if (o instanceof JSONObject) {
-            return (JSONObject)o;
-        }
-        throw new JSONException("JSONArray[" + index +
-            "] is not a JSONObject.");
-    }
-
-
-    /**
-     * Get the long value associated with an index.
-     * 
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The value.
-     * @throws   JSONException If the key is not found or if the value cannot 
-     *  be converted to a number.
-     */
-    public long getLong(int index) throws JSONException {
-        Object o = get(index);
-        return o instanceof Number ? 
-                ((Number)o).longValue() : (long)getDouble(index);
-    }
-
-
-    /**
-     * Get the string associated with an index.
-     * @param index The index must be between 0 and length() - 1.
-     * @return      A string value.
-     * @throws JSONException If there is no value for the index.
-     */
-    public String getString(int index) throws JSONException {
-        return get(index).toString();
-    }
-
-
-    /**
-     * Determine if the value is null.
-     * @param index The index must be between 0 and length() - 1.
-     * @return true if the value at the index is null, or if there is no value.
-     */
-    public boolean isNull(int index) {
-        return JSONObject.NULL.equals(opt(index));
-    }
-
-
-    /**
-     * Make a string from the contents of this JSONArray. The 
-     * <code>separator</code> string is inserted between each element.
-     * Warning: This method assumes that the data structure is acyclical.
-     * @param separator A string that will be inserted between the elements.
-     * @return a string.
-     * @throws JSONException If the array contains an invalid number.
-     */
-    public String join(String separator) throws JSONException {
-        int len = length();
-        StringBuilder sb = new StringBuilder();
-        
-        for (int i = 0; i < len; i += 1) {
-            if (i > 0) {
-                sb.append(separator);
-            }
-            sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
-        }
-        return sb.toString();
-    }
-
-
-    /**
-     * Get the number of elements in the JSONArray, included nulls.
-     *
-     * @return The length (or size).
-     */
     public int length() {
-        return this.myArrayList.size();
+        return values.size();
     }
 
+    public JSONArray put(boolean value) {
+        values.add(value);
+        return this;
+    }
 
-    /**
-     * Get the optional object value associated with an index.
-     * @param index The index must be between 0 and length() - 1.
-     * @return      An object value, or null if there is no
-     *              object at that index.
-     */
+    public JSONArray put(double value) throws JSONException {
+        values.add(JSON.checkDouble(value));
+        return this;
+    }
+
+    public JSONArray put(int value) {
+        values.add(value);
+        return this;
+    }
+
+    public JSONArray put(long value) {
+        values.add(value);
+        return this;
+    }
+
+    public JSONArray put(Object value) {
+        values.add(value);
+        return this;
+    }
+
+    public JSONArray put(int index, boolean value) throws JSONException {
+        return put(index, (Boolean) value);
+    }
+
+    public JSONArray put(int index, double value) throws JSONException {
+        return put(index, (Double) value);
+    }
+
+    public JSONArray put(int index, int value) throws JSONException {
+        return put(index, (Integer) value);
+    }
+
+    public JSONArray put(int index, long value) throws JSONException {
+        return put(index, (Long) value);
+    }
+
+    public JSONArray put(int index, Object value) throws JSONException {
+        if (value instanceof Number) {
+            // deviate from the original by checking all Numbers, not just floats & doubles
+            JSON.checkDouble(((Number) value).doubleValue());
+        }
+        while (values.size() <= index) {
+            values.add(null);
+        }
+        values.set(index, value);
+        return this;
+    }
+
+    public boolean isNull(int index) {
+        Object value = opt(index);
+        return value == null || value == JSONObject.NULL;
+    }
+
+    public Object get(int index) throws JSONException {
+        try {
+            Object value = values.get(index);
+            if (value == null) {
+                throw new JSONException("Value at " + index + " is null.");
+            }
+            return value;
+        } catch (IndexOutOfBoundsException e) {
+            throw new JSONException("Index " + index + " out of range [0.." + values.size() + ")");
+        }
+    }
+
     public Object opt(int index) {
-        return (index < 0 || index >= length()) ? 
-            null : this.myArrayList.get(index);
+        if (index < 0 || index >= values.size()) {
+            return null;
+        }
+        return values.get(index);
     }
 
+    public boolean getBoolean(int index) throws JSONException {
+        Object object = get(index);
+        Boolean result = JSON.toBoolean(object);
+        if (result == null) {
+            throw JSON.typeMismatch(index, object, "boolean");
+        }
+        return result;
+    }
 
-    /**
-     * Get the optional boolean value associated with an index.
-     * It returns false if there is no value at that index,
-     * or if the value is not Boolean.TRUE or the String "true".
-     *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The truth.
-     */
-    public boolean optBoolean(int index)  {
+    public boolean optBoolean(int index) {
         return optBoolean(index, false);
     }
 
-
-    /**
-     * Get the optional boolean value associated with an index.
-     * It returns the defaultValue if there is no value at that index or if 
-     * it is not a Boolean or the String "true" or "false" (case insensitive).
-     *
-     * @param index The index must be between 0 and length() - 1.
-     * @param defaultValue     A boolean default.
-     * @return      The truth.
-     */
-    public boolean optBoolean(int index, boolean defaultValue)  {
-        try {
-            return getBoolean(index);
-        } catch (Exception e) {
-            return defaultValue;
-        }
+    public boolean optBoolean(int index, boolean fallback) {
+        Object object = opt(index);
+        Boolean result = JSON.toBoolean(object);
+        return result != null ? result : fallback;
     }
 
+    public double getDouble(int index) throws JSONException {
+        Object object = get(index);
+        Double result = JSON.toDouble(object);
+        if (result == null) {
+            throw JSON.typeMismatch(index, object, "double");
+        }
+        return result;
+    }
 
-    /**
-     * Get the optional double value associated with an index.
-     * NaN is returned if there is no value for the index,
-     * or if the value is not a number and cannot be converted to a number.
-     *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The value.
-     */
     public double optDouble(int index) {
         return optDouble(index, Double.NaN);
     }
 
-
-    /**
-     * Get the optional double value associated with an index.
-     * The defaultValue is returned if there is no value for the index,
-     * or if the value is not a number and cannot be converted to a number.
-     *
-     * @param index subscript
-     * @param defaultValue     The default value.
-     * @return      The value.
-     */
-    public double optDouble(int index, double defaultValue) {
-        try {
-            return getDouble(index);
-        } catch (Exception e) {
-            return defaultValue;
-        }
+    public double optDouble(int index, double fallback) {
+        Object object = opt(index);
+        Double result = JSON.toDouble(object);
+        return result != null ? result : fallback;
     }
 
+    public int getInt(int index) throws JSONException {
+        Object object = get(index);
+        Integer result = JSON.toInteger(object);
+        if (result == null) {
+            throw JSON.typeMismatch(index, object, "int");
+        }
+        return result;
+    }
 
-    /**
-     * Get the optional int value associated with an index.
-     * Zero is returned if there is no value for the index,
-     * or if the value is not a number and cannot be converted to a number.
-     *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The value.
-     */
     public int optInt(int index) {
         return optInt(index, 0);
     }
 
+    public int optInt(int index, int fallback) {
+        Object object = opt(index);
+        Integer result = JSON.toInteger(object);
+        return result != null ? result : fallback;
+    }
 
-    /**
-     * Get the optional int value associated with an index.
-     * The defaultValue is returned if there is no value for the index,
-     * or if the value is not a number and cannot be converted to a number.
-     * @param index The index must be between 0 and length() - 1.
-     * @param defaultValue     The default value.
-     * @return      The value.
-     */
-    public int optInt(int index, int defaultValue) {
-        try {
-            return getInt(index);
-        } catch (Exception e) {
-            return defaultValue;
+    public long getLong(int index) throws JSONException {
+        Object object = get(index);
+        Long result = JSON.toLong(object);
+        if (result == null) {
+            throw JSON.typeMismatch(index, object, "long");
         }
+        return result;
     }
 
-
-    /**
-     * Get the optional JSONArray associated with an index.
-     * @param index subscript
-     * @return      A JSONArray value, or null if the index has no value,
-     * or if the value is not a JSONArray.
-     */
-    public JSONArray optJSONArray(int index) {
-        Object o = opt(index);
-        return o instanceof JSONArray ? (JSONArray)o : null;
-    }
-
-
-    /**
-     * Get the optional JSONObject associated with an index.
-     * Null is returned if the key is not found, or null if the index has
-     * no value, or if the value is not a JSONObject.
-     *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      A JSONObject value.
-     */
-    public JSONObject optJSONObject(int index) {
-        Object o = opt(index);
-        return o instanceof JSONObject ? (JSONObject)o : null;
-    }
-
-
-    /**
-     * Get the optional long value associated with an index.
-     * Zero is returned if there is no value for the index,
-     * or if the value is not a number and cannot be converted to a number.
-     *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The value.
-     */
     public long optLong(int index) {
-        return optLong(index, 0);
+        return optLong(index, 0L);
     }
 
+    public long optLong(int index, long fallback) {
+        Object object = opt(index);
+        Long result = JSON.toLong(object);
+        return result != null ? result : fallback;
+    }
 
-    /**
-     * Get the optional long value associated with an index.
-     * The defaultValue is returned if there is no value for the index,
-     * or if the value is not a number and cannot be converted to a number.
-     * @param index The index must be between 0 and length() - 1.
-     * @param defaultValue     The default value.
-     * @return      The value.
-     */
-    public long optLong(int index, long defaultValue) {
-        try {
-            return getLong(index);
-        } catch (Exception e) {
-            return defaultValue;
+    public String getString(int index) throws JSONException {
+        Object object = get(index);
+        String result = JSON.toString(object);
+        if (result == null) {
+            throw JSON.typeMismatch(index, object, "String");
         }
+        return result;
     }
 
-
-    /**
-     * Get the optional string value associated with an index. It returns an
-     * empty string if there is no value at that index. If the value
-     * is not a string and is not null, then it is coverted to a string.
-     *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      A String value.
-     */
     public String optString(int index) {
         return optString(index, "");
     }
 
-
-    /**
-     * Get the optional string associated with an index.
-     * The defaultValue is returned if the key is not found.
-     *
-     * @param index The index must be between 0 and length() - 1.
-     * @param defaultValue     The default value.
-     * @return      A String value.
-     */
-    public String optString(int index, String defaultValue) {
-        Object o = opt(index);
-        return o != null ? o.toString() : defaultValue;
+    public String optString(int index, String fallback) {
+        Object object = opt(index);
+        String result = JSON.toString(object);
+        return result != null ? result : fallback;
     }
 
-
-    /**
-     * Append a boolean value. This increases the array's length by one.
-     *
-     * @param value A boolean value.
-     * @return this.
-     */
-    public JSONArray put(boolean value) {
-        put(Boolean.valueOf(value));
-        return this;
-    }
-
-
-    /**
-     * Append a double value. This increases the array's length by one.
-     *
-     * @param value A double value.
-     * @throws JSONException if the value is not finite.
-     * @return this.
-     */
-    public JSONArray put(double value) throws JSONException {
-        Double d = new Double(value);
-        JSONObject.testValidity(d);
-        put(d);
-        return this;
-    }
-
-
-    /**
-     * Append an int value. This increases the array's length by one.
-     *
-     * @param value An int value.
-     * @return this.
-     */
-    public JSONArray put(int value) {
-        put(new Integer(value));
-        return this;
-    }
-
-
-    /**
-     * Append an long value. This increases the array's length by one.
-     *
-     * @param value A long value.
-     * @return this.
-     */
-    public JSONArray put(long value) {
-        put(new Long(value));
-        return this;
-    }
-
-
-    /**
-     * Append an object value. This increases the array's length by one.
-     * @param value An object value.  The value should be a
-     *  Boolean, Double, Integer, JSONArray, JSObject, Long, or String, or the
-     *  JSONObject.NULL object.
-     * @return this.
-     */
-    public JSONArray put(Object value) {
-        this.myArrayList.add(value);
-        return this;
-    }
-
-
-    /**
-     * Put or replace a boolean value in the JSONArray. If the index is greater 
-     * than the length of the JSONArray, then null elements will be added as 
-     * necessary to pad it out.
-     * @param index The subscript. 
-     * @param value A boolean value.
-     * @return this.
-     * @throws JSONException If the index is negative.
-     */
-    public JSONArray put(int index, boolean value) throws JSONException {
-        put(index, Boolean.valueOf(value));
-        return this;
-    }
-
-
-    /**
-     * Put or replace a double value. If the index is greater than the length of
-     *  the JSONArray, then null elements will be added as necessary to pad
-     *  it out.
-     * @param index The subscript. 
-     * @param value A double value.
-     * @return this.
-     * @throws JSONException If the index is negative or if the value is
-     * not finite.
-     */
-    public JSONArray put(int index, double value) throws JSONException {
-        put(index, new Double(value));
-        return this;
-    }
-
-
-    /**
-     * Put or replace an int value. If the index is greater than the length of
-     *  the JSONArray, then null elements will be added as necessary to pad
-     *  it out.
-     * @param index The subscript. 
-     * @param value An int value.
-     * @return this.
-     * @throws JSONException If the index is negative.
-     */
-    public JSONArray put(int index, int value) throws JSONException {
-        put(index, new Integer(value));
-        return this;
-    }
-
-
-    /**
-     * Put or replace a long value. If the index is greater than the length of
-     *  the JSONArray, then null elements will be added as necessary to pad
-     *  it out.
-     * @param index The subscript. 
-     * @param value A long value.
-     * @return this.
-     * @throws JSONException If the index is negative.
-     */
-    public JSONArray put(int index, long value) throws JSONException {
-        put(index, new Long(value));
-        return this;
-    }
-
-
-    /**
-     * Put or replace an object value in the JSONArray. If the index is greater 
-     *  than the length of the JSONArray, then null elements will be added as
-     *  necessary to pad it out.
-     * @param index The subscript. 
-     * @param value The value to put into the array.
-     * @return this.
-     * @throws JSONException If the index is negative or if the the value is
-     *     an invalid number.
-     */
-    public JSONArray put(int index, Object value) throws JSONException {
-        JSONObject.testValidity(value);
-        if (index < 0) {
-            throw new JSONException("JSONArray[" + index + "] not found.");
-        } 
-        if (index < length()) {
-            this.myArrayList.set(index, value);
+    public JSONArray getJSONArray(int index) throws JSONException {
+        Object object = get(index);
+        if (object instanceof JSONArray) {
+            return (JSONArray) object;
         } else {
-            while (index != length()) {
-                put(null);
-            }
-            put(value);
+            throw JSON.typeMismatch(index, object, "JSONArray");
         }
-        return this;
     }
 
+    public JSONArray optJSONArray(int index) {
+        Object object = opt(index);
+        return object instanceof JSONArray ? (JSONArray) object : null;
+    }
 
-    /**
-     * Produce a JSONObject by combining a JSONArray of names with the values
-     * of this JSONArray.
-     * @param names A JSONArray containing a list of key strings. These will be
-     * paired with the values.
-     * @return A JSONObject, or null if there are no names or if this JSONArray
-     * has no values.
-     * @throws JSONException If any of the names are null.
-     */
+    public JSONObject getJSONObject(int index) throws JSONException {
+        Object object = get(index);
+        if (object instanceof JSONObject) {
+            return (JSONObject) object;
+        } else {
+            throw JSON.typeMismatch(index, object, "JSONObject");
+        }
+    }
+
+    public JSONObject optJSONObject(int index) {
+        Object object = opt(index);
+        return object instanceof JSONObject ? (JSONObject) object : null;
+    }
+
     public JSONObject toJSONObject(JSONArray names) throws JSONException {
-        if (names == null || names.length() == 0 || length() == 0) {
+        JSONObject result = new JSONObject();
+        int length = Math.min(names.length(), values.size());
+        if (length == 0) {
             return null;
         }
-        JSONObject jo = new JSONObject();
-        for (int i = 0; i < names.length(); i += 1) {
-            jo.put(names.getString(i), this.opt(i));
+        for (int i = 0; i < length; i++) {
+            String name = JSON.toString(names.opt(i));
+            result.put(name, opt(i));
         }
-        return jo;
+        return result;
     }
 
+    public String join(String separator) throws JSONException {
+        JSONStringer stringer = new JSONStringer();
+        stringer.open(JSONStringer.Scope.NULL, "");
+        for (int i = 0, size = values.size(); i < size; i++) {
+            if (i > 0) {
+                stringer.out.append(separator);
+            }
+            stringer.value(values.get(i));
+        }
+        stringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, "");
+        return stringer.out.toString();
+    }
 
-    /**
-     * Make an JSON text of this JSONArray. For compactness, no
-     * unnecessary whitespace is added. If it is not possible to produce a
-     * syntactically correct JSON text then null will be returned instead. This
-     * could occur if the array contains an invalid number.
-     * <p>
-     * Warning: This method assumes that the data structure is acyclical.
-     *
-     * @return a printable, displayable, transmittable
-     *  representation of the array.
-     */
-    public String toString() {
+    @Override public String toString() {
         try {
-            return '[' + join(",") + ']';
-        } catch (Exception e) {
+            JSONStringer stringer = new JSONStringer();
+            writeTo(stringer);
+            return stringer.toString();
+        } catch (JSONException e) {
             return null;
         }
     }
 
-
-    /**
-     * Make a prettyprinted JSON text of this JSONArray.
-     * Warning: This method assumes that the data structure is acyclical.
-     * @param indentFactor The number of spaces to add to each level of
-     *  indentation.
-     * @return a printable, displayable, transmittable
-     *  representation of the object, beginning
-     *  with <code>[</code>&nbsp;<small>(left bracket)</small> and ending
-     *  with <code>]</code>&nbsp;<small>(right bracket)</small>.
-     * @throws JSONException
-     */
-    public String toString(int indentFactor) throws JSONException {
-        return toString(indentFactor, 0);
+    public String toString(int indentSpaces) throws JSONException {
+        JSONStringer stringer = new JSONStringer(indentSpaces);
+        writeTo(stringer);
+        return stringer.toString();
     }
 
+    void writeTo(JSONStringer stringer) throws JSONException {
+        stringer.array();
+        for (Object value : values) {
+            stringer.value(value);
+        }
+        stringer.endArray();
+    }
 
-    /**
-     * Make a prettyprinted JSON text of this JSONArray.
-     * Warning: This method assumes that the data structure is acyclical.
-     * @param indentFactor The number of spaces to add to each level of
-     *  indentation.
-     * @param indent The indention of the top level.
-     * @return a printable, displayable, transmittable
-     *  representation of the array.
-     * @throws JSONException
-     */
-    String toString(int indentFactor, int indent) throws JSONException {
-        int len = length();
-        if (len == 0) {
-            return "[]";
-        }
-        int i;
-        StringBuilder sb = new StringBuilder("[");
-        if (len == 1) {
-            sb.append(JSONObject.valueToString(this.myArrayList.get(0),
-                    indentFactor, indent));
-        } else {
-            int newindent = indent + indentFactor;
-            sb.append('\n');
-            for (i = 0; i < len; i += 1) {
-                if (i > 0) {
-                    sb.append(",\n");
-                }
-                for (int j = 0; j < newindent; j += 1) {
-                    sb.append(' ');
-                }
-                sb.append(JSONObject.valueToString(this.myArrayList.get(i),
-                        indentFactor, newindent));
-            }
-            sb.append('\n');
-            for (i = 0; i < indent; i += 1) {
-                sb.append(' ');
-            }
-        }
-        sb.append(']');
-        return sb.toString();
+    @Override public boolean equals(Object o) {
+        return o instanceof JSONArray && ((JSONArray) o).values.equals(values);
+    }
+
+    @Override public int hashCode() {
+        // diverge from the original, which doesn't implement hashCode
+        return values.hashCode();
     }
 }
diff --git a/libcore/json/src/main/java/org/json/JSONException.java b/libcore/json/src/main/java/org/json/JSONException.java
index a2905bf..e1efd9f 100644
--- a/libcore/json/src/main/java/org/json/JSONException.java
+++ b/libcore/json/src/main/java/org/json/JSONException.java
@@ -1,16 +1,49 @@
+/*
+ * 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 org.json;
 
+// Note: this class was written without inspecting the non-free org.json sourcecode.
+
 /**
- * The JSONException is thrown by the JSON.org classes then things are amiss.
- * @author JSON.org
- * @version 2
+ * Thrown to indicate a problem with the JSON API. Such problems include:
+ * <ul>
+ *   <li>Attempts to parse or construct malformed documents
+ *   <li>Use of null as a name
+ *   <li>Use of numeric types not available to JSON, such as {@link Double#NaN
+ *       NaN} or {@link Double#POSITIVE_INFINITY infinity}.
+ *   <li>Lookups using an out of range index or nonexistant name
+ *   <li>Type mismatches on lookups
+ * </ul>
+ *
+ * <p>Although this is a checked exception, it is rarely recoverable. Most
+ * callers should simply wrap this exception in an unchecked exception and
+ * rethrow:
+ * <pre>  public JSONArray toJSONObject() {
+ *     try {
+ *         JSONObject result = new JSONObject();
+ *         ...
+ *     } catch (JSONException e) {
+ *         throw new RuntimeException(e);
+ *     }
+ * }</pre>
  */
 public class JSONException extends Exception {
-    /**
-     * Constructs a JSONException with an explanatory message.
-     * @param message Detail about the reason for the exception.
-     */
-    public JSONException(String message) {
-        super(message);
+
+    public JSONException(String s) {
+        super(s);
     }
 }
diff --git a/libcore/json/src/main/java/org/json/JSONObject.java b/libcore/json/src/main/java/org/json/JSONObject.java
index b0ebea2..c92d549 100644
--- a/libcore/json/src/main/java/org/json/JSONObject.java
+++ b/libcore/json/src/main/java/org/json/JSONObject.java
@@ -1,1081 +1,395 @@
+/*
+ * 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 org.json;
 
-/*
-Copyright (c) 2002 JSON.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-The Software shall be used for Good, not Evil.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 
-// BEGIN android-note
-//   - fixed bad htm in javadoc comments -joeo
-// END android-note
+// Note: this class was written without inspecting the non-free org.json sourcecode.
 
 /**
- * A JSONObject is an unordered collection of name/value pairs. Its
- * external form is a string wrapped in curly braces with colons between the
- * names and values, and commas between the values and names. The internal form
- * is an object having <code>get</code> and <code>opt</code> methods for 
- * accessing the values by name, and <code>put</code> methods for adding or 
- * replacing values by name. The values can be any of these types: 
- * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>, 
- * <code>Number</code>, <code>String</code>, or the <code>JSONObject.NULL</code> 
- * object. A JSONObject constructor can be used to convert an external form
- * JSON text into an internal form whose values can be retrieved with the 
- * <code>get</code> and <code>opt</code> methods, or to convert values into a 
- * JSON text using the <code>put</code> and <code>toString</code> methods.
- * A <code>get</code> method returns a value if one can be found, and throws an 
- * exception if one cannot be found. An <code>opt</code> method returns a 
- * default value instead of throwing an exception, and so is useful for 
- * obtaining optional values.
- * <p>
- * The generic <code>get()</code> and <code>opt()</code> methods return an 
- * object, which you can cast or query for type. There are also typed 
- * <code>get</code> and <code>opt</code> methods that do type checking and type 
- * coersion for you.
- * <p>
- * The <code>put</code> methods adds values to an object. For example, <pre>
- *     myString = new JSONObject().put("JSON", "Hello, World!").toString();</pre>
- * produces the string <code>{"JSON": "Hello, World"}</code>.
- * <p>
- * The texts produced by the <code>toString</code> methods strictly conform to
- * the JSON sysntax rules.
- * The constructors are more forgiving in the texts they will accept:
- * <ul>
- * <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just
- *     before the closing brace.</li>
- * <li>Strings may be quoted with <code>'</code>&nbsp;<small>(single
- *     quote)</small>.</li>
- * <li>Strings do not need to be quoted at all if they do not begin with a quote
- *     or single quote, and if they do not contain leading or trailing spaces,
- *     and if they do not contain any of these characters:
- *     <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers
- *     and if they are not the reserved words <code>true</code>,
- *     <code>false</code>, or <code>null</code>.</li>
- * <li>Keys can be followed by <code>=</code> or <code>=></code> as well as
- *     by <code>:</code>.</li>
- * <li>Values can be followed by <code>;</code> <small>(semicolon)</small> as 
- *     well as by <code>,</code> <small>(comma)</small>.</li>
- * <li>Numbers may have the <code>0-</code> <small>(octal)</small> or
- *     <code>0x-</code> <small>(hex)</small> prefix.</li>
- * <li>Comments written in the slashshlash, slashstar, and hash conventions
- *     will be ignored.</li>
- * </ul>
- * @author JSON.org
- * @version 2
+ *
+ *
+ * <p>TODO: Note about self-use
  */
 public class JSONObject {
 
-    /**
-     * JSONObject.NULL is equivalent to the value that JavaScript calls null,
-     * whilst Java's null is equivalent to the value that JavaScript calls
-     * undefined.
-     */
-     private static final class Null {
+    private static final Double NEGATIVE_ZERO = -0d;
 
-        /**
-         * There is only intended to be a single instance of the NULL object,
-         * so the clone method returns itself.
-         * @return     NULL.
+    public static final Object NULL = new Object() {
+        @Override public boolean equals(Object o) {
+            return o == this || o == null; // API specifies this broken equals implementation
+        }
+        @Override public String toString() {
+            return "null";
+        }
+    };
+
+    private final Map<String, Object> nameValuePairs;
+
+    public JSONObject() {
+        nameValuePairs = new HashMap<String, Object>();
+    }
+
+    /* Accept a raw type for API compatibility */
+    public JSONObject(Map copyFrom) {
+        this();
+        Map<?, ?> contentsTyped = (Map<?, ?>) copyFrom;
+        for (Map.Entry<?, ?> entry : contentsTyped.entrySet()) {
+            /*
+             * Deviate from the original by checking that keys are non-null and
+             * of the proper type. (We still defer validating the values).
+             */
+            String key = (String) entry.getKey();
+            if (key == null) {
+                throw new NullPointerException();
+            }
+            nameValuePairs.put(key, entry.getValue());
+        }
+    }
+
+    public JSONObject(JSONTokener readFrom) throws JSONException {
+        /*
+         * Getting the parser to populate this could get tricky. Instead, just
+         * parse to temporary JSONObject and then steal the data from that.
          */
-        protected final Object clone() {
+        Object object = readFrom.nextValue();
+        if (object instanceof JSONObject) {
+            this.nameValuePairs = ((JSONObject) object).nameValuePairs;
+        } else {
+            throw JSON.typeMismatch(object, "JSONObject");
+        }
+    }
+
+    public JSONObject(String json) throws JSONException {
+        this(new JSONTokener(json));
+    }
+
+    public JSONObject(JSONObject copyFrom, String[] names) throws JSONException {
+        this();
+        for (String name : names) {
+            Object value = copyFrom.opt(name);
+            if (value != null) {
+                nameValuePairs.put(name, value);
+            }
+        }
+    }
+
+    public int length() {
+        return nameValuePairs.size();
+    }
+
+    public JSONObject put(String name, boolean value) throws JSONException {
+        nameValuePairs.put(checkName(name), value);
+        return this;
+    }
+
+    public JSONObject put(String name, double value) throws JSONException {
+        nameValuePairs.put(checkName(name), JSON.checkDouble(value));
+        return this;
+    }
+
+    public JSONObject put(String name, int value) throws JSONException {
+        nameValuePairs.put(checkName(name), value);
+        return this;
+    }
+
+    public JSONObject put(String name, long value) throws JSONException {
+        nameValuePairs.put(checkName(name), value);
+        return this;
+    }
+
+    public JSONObject put(String name, Object value) throws JSONException {
+        if (value == null) {
+            nameValuePairs.remove(name);
             return this;
         }
-
-
-        /**
-         * A Null object is equal to the null value and to itself.
-         * @param object    An object to test for nullness.
-         * @return true if the object parameter is the JSONObject.NULL object
-         *  or null.
-         */
-        public boolean equals(Object object) {
-            return object == null || object == this;
+        if (value instanceof Number) {
+            // deviate from the original by checking all Numbers, not just floats & doubles
+            JSON.checkDouble(((Number) value).doubleValue());
         }
+        nameValuePairs.put(checkName(name), value);
+        return this;
+    }
 
-
-        /**
-         * Get the "null" string value.
-         * @return The string "null".
-         */
-        public String toString() {
-            return "null";
+    public JSONObject putOpt(String name, Object value) throws JSONException {
+        if (name == null || value == null) {
+            return this;
         }
+        return put(name, value);
     }
 
-
-    /**
-     * The hash map where the JSONObject's properties are kept.
-     */
-    private HashMap myHashMap;
-
-
-    /**
-     * It is sometimes more convenient and less ambiguous to have a 
-     * <code>NULL</code> object than to use Java's <code>null</code> value.
-     * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>.
-     * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>.
-     */
-    public static final Object NULL = new Null();
-
-
-    /**
-     * Construct an empty JSONObject.
-     */
-    public JSONObject() {
-        this.myHashMap = new HashMap();
-    }
-
-
-    /**
-     * Construct a JSONObject from a subset of another JSONObject.
-     * An array of strings is used to identify the keys that should be copied. 
-     * Missing keys are ignored.
-     * @param jo A JSONObject.
-     * @param sa An array of strings.
-     * @exception JSONException If a value is a non-finite number.
-     */
-    public JSONObject(JSONObject jo, String[] sa) throws JSONException {
-        this();
-        for (int i = 0; i < sa.length; i += 1) {
-            putOpt(sa[i], jo.opt(sa[i]));
-        }
-    }
-
-
-    /**
-     * Construct a JSONObject from a JSONTokener.
-     * @param x A JSONTokener object containing the source string.
-     * @throws JSONException If there is a syntax error in the source string.
-     */
-    public JSONObject(JSONTokener x) throws JSONException {
-        this();
-        char c;
-        String key;
-
-        if (x.nextClean() != '{') {
-            throw x.syntaxError("A JSONObject text must begin with '{'");
-        }
-        for (;;) {
-            c = x.nextClean();
-            switch (c) {
-            case 0:
-                throw x.syntaxError("A JSONObject text must end with '}'");
-            case '}':
-                return;
-            default:
-                x.back();
-                key = x.nextValue().toString();
-            }
-
-            /*
-             * The key is followed by ':'. We will also tolerate '=' or '=>'.
-             */
-
-            c = x.nextClean();
-            if (c == '=') {
-                if (x.next() != '>') {
-                    x.back();
-                }
-            } else if (c != ':') {
-                throw x.syntaxError("Expected a ':' after a key");
-            }
-            this.myHashMap.put(key, x.nextValue());
-
-            /*
-             * Pairs are separated by ','. We will also tolerate ';'.
-             */
-
-            switch (x.nextClean()) {
-            case ';':
-            case ',':
-                if (x.nextClean() == '}') {
-                    return;
-                }
-                x.back();
-                break;
-            case '}':
-                return;
-            default:
-                throw x.syntaxError("Expected a ',' or '}'");
-            }
-        }
-    }
-
-
-    /**
-     * Construct a JSONObject from a Map.
-     * @param map A map object that can be used to initialize the contents of
-     *  the JSONObject.
-     */
-    public JSONObject(Map map) {
-        this.myHashMap = new HashMap(map);
-    }
-
-
-    /**
-     * Construct a JSONObject from a string.
-     * This is the most commonly used JSONObject constructor.
-     * @param string    A string beginning
-     *  with <code>{</code>&nbsp;<small>(left brace)</small> and ending
-     *  with <code>}</code>&nbsp;<small>(right brace)</small>.
-     * @exception JSONException If there is a syntax error in the source string.
-     */
-    public JSONObject(String string) throws JSONException {
-        this(new JSONTokener(string));
-    }
-
-
-    /**
-     * Accumulate values under a key. It is similar to the put method except
-     * that if there is already an object stored under the key then a
-     * JSONArray is stored under the key to hold all of the accumulated values.
-     * If there is already a JSONArray, then the new value is appended to it.
-     * In contrast, the put method replaces the previous value.
-     * @param key   A key string.
-     * @param value An object to be accumulated under the key.
-     * @return this.
-     * @throws JSONException If the value is an invalid number 
-     *  or if the key is null.
-     */
-    public JSONObject accumulate(String key, Object value) 
-            throws JSONException {
-        testValidity(value);
-        Object o = opt(key);
-        if (o == null) {
-            put(key, value);
-        } else if (o instanceof JSONArray) {
-            ((JSONArray)o).put(value);
+    public JSONObject accumulate(String name, Object value) throws JSONException {
+        Object current = nameValuePairs.get(checkName(name));
+        if (current == null) {
+            put(name, value);
+        } else if (current instanceof JSONArray) {
+            JSONArray array = (JSONArray) current;
+            array.put(value);
         } else {
-            put(key, new JSONArray().put(o).put(value));
+            JSONArray array = new JSONArray();
+            array.put(current);
+            array.put(value); // fails on bogus values
+            nameValuePairs.put(name, array);
         }
         return this;
     }
 
-
-    /**
-     * Get the value object associated with a key.
-     *
-     * @param key   A key string.
-     * @return      The object associated with the key.
-     * @throws   JSONException if the key is not found.
-     */
-    public Object get(String key) throws JSONException {
-        Object o = opt(key);
-        if (o == null) {
-            throw new JSONException("JSONObject[" + quote(key) + 
-                    "] not found.");
+    String checkName(String name) throws JSONException {
+        if (name == null) {
+            throw new JSONException("Names must be non-null");
         }
-        return o;
+        return name;
     }
 
-
-    /**
-     * Get the boolean value associated with a key.
-     *
-     * @param key   A key string.
-     * @return      The truth.
-     * @throws   JSONException
-     *  if the value is not a Boolean or the String "true" or "false".
-     */
-    public boolean getBoolean(String key) throws JSONException {
-        Object o = get(key);
-        if (o.equals(Boolean.FALSE) ||
-                (o instanceof String &&
-                ((String)o).equalsIgnoreCase("false"))) {
-            return false;
-        } else if (o.equals(Boolean.TRUE) ||
-                (o instanceof String &&
-                ((String)o).equalsIgnoreCase("true"))) {
-            return true;
-        }
-        throw new JSONException("JSONObject[" + quote(key) + 
-                "] is not a Boolean.");
+    public Object remove(String name) {
+        return nameValuePairs.remove(name);
     }
 
+    public boolean isNull(String name) {
+        Object value = nameValuePairs.get(name);
+        return value == null || value == NULL;
+    }
 
-    /**
-     * Get the double value associated with a key.
-     * @param key   A key string.
-     * @return      The numeric value.
-     * @throws JSONException if the key is not found or
-     *  if the value is not a Number object and cannot be converted to a number.
-     */
-    public double getDouble(String key) throws JSONException {
-        Object o = get(key);
-        try {
-            return o instanceof Number ? 
-                    ((Number)o).doubleValue() : Double.parseDouble((String)o);
-        } catch (Exception e) {
-            throw new JSONException("JSONObject[" + quote(key) + 
-                "] is not a number.");
+    public boolean has(String name) {
+        return nameValuePairs.containsKey(name);
+    }
+
+    public Object get(String name) throws JSONException {
+        Object result = nameValuePairs.get(name);
+        if (result == null) {
+            throw new JSONException("No value for " + name);
+        }
+        return result;
+    }
+
+    public Object opt(String name) {
+        return nameValuePairs.get(name);
+    }
+
+    public boolean getBoolean(String name) throws JSONException {
+        Object object = get(name);
+        Boolean result = JSON.toBoolean(object);
+        if (result == null) {
+            throw JSON.typeMismatch(name, object, "boolean");
+        }
+        return result;
+    }
+
+    public boolean optBoolean(String name) {
+        return optBoolean(name, false);
+    }
+
+    public boolean optBoolean(String name, boolean fallback) {
+        Object object = opt(name);
+        Boolean result = JSON.toBoolean(object);
+        return result != null ? result : fallback;
+    }
+
+    public double getDouble(String name) throws JSONException {
+        Object object = get(name);
+        Double result = JSON.toDouble(object);
+        if (result == null) {
+            throw JSON.typeMismatch(name, object, "double");
+        }
+        return result;
+    }
+
+    public double optDouble(String name) {
+        return optDouble(name, Double.NaN);
+    }
+
+    public double optDouble(String name, double fallback) {
+        Object object = opt(name);
+        Double result = JSON.toDouble(object);
+        return result != null ? result : fallback;
+    }
+
+    public int getInt(String name) throws JSONException {
+        Object object = get(name);
+        Integer result = JSON.toInteger(object);
+        if (result == null) {
+            throw JSON.typeMismatch(name, object, "int");
+        }
+        return result;
+    }
+
+    public int optInt(String name) {
+        return optInt(name, 0);
+    }
+
+    public int optInt(String name, int fallback) {
+        Object object = opt(name);
+        Integer result = JSON.toInteger(object);
+        return result != null ? result : fallback;
+    }
+
+    public long getLong(String name) throws JSONException {
+        Object object = get(name);
+        Long result = JSON.toLong(object);
+        if (result == null) {
+            throw JSON.typeMismatch(name, object, "long");
+        }
+        return result;
+    }
+
+    public long optLong(String name) {
+        return optLong(name, 0L);
+    }
+
+    public long optLong(String name, long fallback) {
+        Object object = opt(name);
+        Long result = JSON.toLong(object);
+        return result != null ? result : fallback;
+    }
+
+    public String getString(String name) throws JSONException {
+        Object object = get(name);
+        String result = JSON.toString(object);
+        if (result == null) {
+            throw JSON.typeMismatch(name, object, "String");
+        }
+        return result;
+    }
+
+    public String optString(String name) {
+        return optString(name, "");
+    }
+
+    public String optString(String name, String fallback) {
+        Object object = opt(name);
+        String result = JSON.toString(object);
+        return result != null ? result : fallback;
+    }
+
+    public JSONArray getJSONArray(String name) throws JSONException {
+        Object object = get(name);
+        if (object instanceof JSONArray) {
+            return (JSONArray) object;
+        } else {
+            throw JSON.typeMismatch(name, object, "JSONArray");
         }
     }
 
-
-    /**
-     * Get the int value associated with a key. If the number value is too
-     * large for an int, it will be clipped.
-     *
-     * @param key   A key string.
-     * @return      The integer value.
-     * @throws   JSONException if the key is not found or if the value cannot
-     *     be converted to an integer.
-     */
-    public int getInt(String key) throws JSONException {
-        Object o = get(key);
-        return o instanceof Number ? 
-                ((Number)o).intValue() : (int)getDouble(key);
+    public JSONArray optJSONArray(String name) {
+        Object object = opt(name);
+        return object instanceof JSONArray ? (JSONArray) object : null;
     }
 
-
-    /**
-     * Get the JSONArray value associated with a key.
-     *
-     * @param key   A key string.
-     * @return      A JSONArray which is the value.
-     * @throws   JSONException if the key is not found or
-     *  if the value is not a JSONArray.
-     */
-    public JSONArray getJSONArray(String key) throws JSONException {
-        Object o = get(key);
-        if (o instanceof JSONArray) {
-            return (JSONArray)o;
+    public JSONObject getJSONObject(String name) throws JSONException {
+        Object object = get(name);
+        if (object instanceof JSONObject) {
+            return (JSONObject) object;
+        } else {
+            throw JSON.typeMismatch(name, object, "JSONObject");
         }
-        throw new JSONException("JSONObject[" + quote(key) + 
-                "] is not a JSONArray.");
     }
 
+    public JSONObject optJSONObject(String name) {
+        Object object = opt(name);
+        return object instanceof JSONObject ? (JSONObject) object : null;
+    }
 
-    /**
-     * Get the JSONObject value associated with a key.
-     *
-     * @param key   A key string.
-     * @return      A JSONObject which is the value.
-     * @throws   JSONException if the key is not found or
-     *  if the value is not a JSONObject.
-     */
-    public JSONObject getJSONObject(String key) throws JSONException {
-        Object o = get(key);
-        if (o instanceof JSONObject) {
-            return (JSONObject)o;
+    public JSONArray toJSONArray(JSONArray names) throws JSONException {
+        JSONArray result = new JSONArray();
+        if (names == null) {
+            return null;
         }
-        throw new JSONException("JSONObject[" + quote(key) + 
-                "] is not a JSONObject.");
+        int length = names.length();
+        if (length == 0) {
+            return null;
+        }
+        for (int i = 0; i < length; i++) {
+            String name = JSON.toString(names.opt(i));
+            result.put(opt(name));
+        }
+        return result;
     }
 
-
-    /**
-     * Get the long value associated with a key. If the number value is too
-     * long for a long, it will be clipped.
-     *
-     * @param key   A key string.
-     * @return      The long value.
-     * @throws   JSONException if the key is not found or if the value cannot
-     *     be converted to a long.
-     */
-    public long getLong(String key) throws JSONException {
-        Object o = get(key);
-        return o instanceof Number ? 
-                ((Number)o).longValue() : (long)getDouble(key);
-    }
-
-
-    /**
-     * Get the string associated with a key.
-     *
-     * @param key   A key string.
-     * @return      A string which is the value.
-     * @throws   JSONException if the key is not found.
-     */
-    public String getString(String key) throws JSONException {
-        return get(key).toString();
-    }
-
-
-    /**
-     * Determine if the JSONObject contains a specific key.
-     * @param key   A key string.
-     * @return      true if the key exists in the JSONObject.
-     */
-    public boolean has(String key) {
-        return this.myHashMap.containsKey(key);
-    }
-
-
-    /**
-     * Determine if the value associated with the key is null or if there is
-     *  no value.
-     * @param key   A key string.
-     * @return      true if there is no value associated with the key or if
-     *  the value is the JSONObject.NULL object.
-     */
-    public boolean isNull(String key) {
-        return JSONObject.NULL.equals(opt(key));
-    }
-
-
-    /**
-     * Get an enumeration of the keys of the JSONObject.
-     *
-     * @return An iterator of the keys.
-     */
+    /* Return a raw type for API compatibility */
     public Iterator keys() {
-        return this.myHashMap.keySet().iterator();
+        return nameValuePairs.keySet().iterator();
     }
 
-
-    /**
-     * Get the number of keys stored in the JSONObject.
-     *
-     * @return The number of keys in the JSONObject.
-     */
-    public int length() {
-        return this.myHashMap.size();
-    }
-
-
-    /**
-     * Produce a JSONArray containing the names of the elements of this
-     * JSONObject.
-     * @return A JSONArray containing the key strings, or null if the JSONObject
-     * is empty.
-     */
     public JSONArray names() {
-        JSONArray ja = new JSONArray();
-        Iterator  keys = keys();
-        while (keys.hasNext()) {
-            ja.put(keys.next());
-        }
-        return ja.length() == 0 ? null : ja;
+        return nameValuePairs.isEmpty()
+                ? null
+                : new JSONArray(new ArrayList<String>(nameValuePairs.keySet()));
     }
 
-    /**
-     * Produce a string from a number.
-     * @param  n A Number
-     * @return A String.
-     * @throws JSONException If n is a non-finite number.
-     */
-    static public String numberToString(Number n) 
-            throws JSONException {
-        if (n == null) {
-            throw new JSONException("Null pointer");
-        }
-        testValidity(n);
-
-// Shave off trailing zeros and decimal point, if possible.
-
-        String s = n.toString();
-        if (s.indexOf('.') > 0 && s.indexOf('e') < 0 && s.indexOf('E') < 0) {
-            while (s.endsWith("0")) {
-                s = s.substring(0, s.length() - 1);
-            }
-            if (s.endsWith(".")) {
-                s = s.substring(0, s.length() - 1);
-            }
-        }
-        return s;
-    }
-
-
-    /**
-     * Get an optional value associated with a key.
-     * @param key   A key string.
-     * @return      An object which is the value, or null if there is no value.
-     */
-    public Object opt(String key) {
-        return key == null ? null : this.myHashMap.get(key);
-    }
-
-
-    /**
-     * Get an optional boolean associated with a key.
-     * It returns false if there is no such key, or if the value is not
-     * Boolean.TRUE or the String "true".
-     *
-     * @param key   A key string.
-     * @return      The truth.
-     */
-    public boolean optBoolean(String key) {
-        return optBoolean(key, false);
-    }
-
-
-    /**
-     * Get an optional boolean associated with a key.
-     * It returns the defaultValue if there is no such key, or if it is not
-     * a Boolean or the String "true" or "false" (case insensitive).
-     *
-     * @param key              A key string.
-     * @param defaultValue     The default.
-     * @return      The truth.
-     */
-    public boolean optBoolean(String key, boolean defaultValue) {
+    @Override public String toString() {
         try {
-            return getBoolean(key);
-        } catch (Exception e) {
-            return defaultValue;
+            JSONStringer stringer = new JSONStringer();
+            writeTo(stringer);
+            return stringer.toString();
+        } catch (JSONException e) {
+            return null;
         }
     }
 
-
-    /**
-     * Get an optional double associated with a key,
-     * or NaN if there is no such key or if its value is not a number.
-     * If the value is a string, an attempt will be made to evaluate it as
-     * a number.
-     *
-     * @param key   A string which is the key.
-     * @return      An object which is the value.
-     */
-    public double optDouble(String key) {
-        return optDouble(key, Double.NaN);
+    public String toString(int indentSpaces) throws JSONException {
+        JSONStringer stringer = new JSONStringer(indentSpaces);
+        writeTo(stringer);
+        return stringer.toString();
     }
 
-
-    /**
-     * Get an optional double associated with a key, or the
-     * defaultValue if there is no such key or if its value is not a number.
-     * If the value is a string, an attempt will be made to evaluate it as
-     * a number.
-     *
-     * @param key   A key string.
-     * @param defaultValue     The default.
-     * @return      An object which is the value.
-     */
-    public double optDouble(String key, double defaultValue) {
-        try {
-            Object o = opt(key);
-            return o instanceof Number ? ((Number)o).doubleValue() :
-                new Double((String)o).doubleValue();
-        } catch (Exception e) {
-            return defaultValue;
+    void writeTo(JSONStringer stringer) throws JSONException {
+        stringer.object();
+        for (Map.Entry<String, Object> entry : nameValuePairs.entrySet()) {
+            stringer.key(entry.getKey()).value(entry.getValue());
         }
+        stringer.endObject();
     }
 
-
-    /**
-     * Get an optional int value associated with a key,
-     * or zero if there is no such key or if the value is not a number.
-     * If the value is a string, an attempt will be made to evaluate it as
-     * a number.
-     *
-     * @param key   A key string.
-     * @return      An object which is the value.
-     */
-    public int optInt(String key) {
-        return optInt(key, 0);
-    }
-
-
-    /**
-     * Get an optional int value associated with a key,
-     * or the default if there is no such key or if the value is not a number.
-     * If the value is a string, an attempt will be made to evaluate it as
-     * a number.
-     *
-     * @param key   A key string.
-     * @param defaultValue     The default.
-     * @return      An object which is the value.
-     */
-    public int optInt(String key, int defaultValue) {
-        try {
-            return getInt(key);
-        } catch (Exception e) {
-            return defaultValue;
+    public static String numberToString(Number number) throws JSONException {
+        if (number == null) {
+            throw new JSONException("Number must be non-null");
         }
-    }
 
+        double doubleValue = number.doubleValue();
+        JSON.checkDouble(doubleValue);
 
-    /**
-     * Get an optional JSONArray associated with a key.
-     * It returns null if there is no such key, or if its value is not a
-     * JSONArray.
-     *
-     * @param key   A key string.
-     * @return      A JSONArray which is the value.
-     */
-    public JSONArray optJSONArray(String key) {
-        Object o = opt(key);
-        return o instanceof JSONArray ? (JSONArray)o : null;
-    }
-
-
-    /**
-     * Get an optional JSONObject associated with a key.
-     * It returns null if there is no such key, or if its value is not a
-     * JSONObject.
-     *
-     * @param key   A key string.
-     * @return      A JSONObject which is the value.
-     */
-    public JSONObject optJSONObject(String key) {
-        Object o = opt(key);
-        return o instanceof JSONObject ? (JSONObject)o : null;
-    }
-
-
-    /**
-     * Get an optional long value associated with a key,
-     * or zero if there is no such key or if the value is not a number.
-     * If the value is a string, an attempt will be made to evaluate it as
-     * a number.
-     *
-     * @param key   A key string.
-     * @return      An object which is the value.
-     */
-    public long optLong(String key) {
-        return optLong(key, 0);
-    }
-
-
-    /**
-     * Get an optional long value associated with a key,
-     * or the default if there is no such key or if the value is not a number.
-     * If the value is a string, an attempt will be made to evaluate it as
-     * a number.
-     *
-     * @param key   A key string.
-     * @param defaultValue     The default.
-     * @return      An object which is the value.
-     */
-    public long optLong(String key, long defaultValue) {
-        try {
-            return getLong(key);
-        } catch (Exception e) {
-            return defaultValue;
+        // the original returns "-0" instead of "-0.0" for negative zero
+        if (number.equals(NEGATIVE_ZERO)) {
+            return "-0";
         }
-    }
 
-
-    /**
-     * Get an optional string associated with a key.
-     * It returns an empty string if there is no such key. If the value is not
-     * a string and is not null, then it is coverted to a string.
-     *
-     * @param key   A key string.
-     * @return      A string which is the value.
-     */
-    public String optString(String key) {
-        return optString(key, "");
-    }
-
-
-    /**
-     * Get an optional string associated with a key.
-     * It returns the defaultValue if there is no such key.
-     *
-     * @param key   A key string.
-     * @param defaultValue     The default.
-     * @return      A string which is the value.
-     */
-    public String optString(String key, String defaultValue) {
-        Object o = opt(key);
-        return o != null ? o.toString() : defaultValue;
-    }
-
-
-    /**
-     * Put a key/boolean pair in the JSONObject.
-     *
-     * @param key   A key string.
-     * @param value A boolean which is the value.
-     * @return this.
-     * @throws JSONException If the key is null.
-     */
-    public JSONObject put(String key, boolean value) throws JSONException {
-        put(key, Boolean.valueOf(value));
-        return this;
-    }
-
-
-    /**
-     * Put a key/double pair in the JSONObject.
-     *
-     * @param key   A key string.
-     * @param value A double which is the value.
-     * @return this.
-     * @throws JSONException If the key is null or if the number is invalid.
-     */
-    public JSONObject put(String key, double value) throws JSONException {
-        put(key, new Double(value));
-        return this;
-    }
-
-
-    /**
-     * Put a key/int pair in the JSONObject.
-     *
-     * @param key   A key string.
-     * @param value An int which is the value.
-     * @return this.
-     * @throws JSONException If the key is null.
-     */
-    public JSONObject put(String key, int value) throws JSONException {
-        put(key, new Integer(value));
-        return this;
-    }
-
-
-    /**
-     * Put a key/long pair in the JSONObject.
-     *
-     * @param key   A key string.
-     * @param value A long which is the value.
-     * @return this.
-     * @throws JSONException If the key is null.
-     */
-    public JSONObject put(String key, long value) throws JSONException {
-        put(key, new Long(value));
-        return this;
-    }
-
-
-    /**
-     * Put a key/value pair in the JSONObject. If the value is null,
-     * then the key will be removed from the JSONObject if it is present.
-     * @param key   A key string.
-     * @param value An object which is the value. It should be of one of these
-     *  types: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, 
-     *  or the JSONObject.NULL object.
-     * @return this.
-     * @throws JSONException If the value is non-finite number 
-     *     or if the key is null.
-     */
-    public JSONObject put(String key, Object value) 
-            throws JSONException {
-        if (key == null) {
-            throw new JSONException("Null key.");
+        long longValue = number.longValue();
+        if (doubleValue == (double) longValue) {
+            return Long.toString(longValue);
         }
-        if (value != null) {
-            testValidity(value);
-            this.myHashMap.put(key, value);
-        } else {
-            remove(key);
-        }
-        return this;
+
+        return number.toString();
     }
 
-
-    /**
-     * Put a key/value pair in the JSONObject, but only if the
-     * key and the value are both non-null.
-     * @param key   A key string.
-     * @param value An object which is the value. It should be of one of these
-     *  types: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, 
-     *  or the JSONObject.NULL object.
-     * @return this.
-     * @throws JSONException If the value is a non-finite number.
-     */
-    public JSONObject putOpt(String key, Object value) throws JSONException {
-        if (key != null && value != null) {
-            put(key, value);
-        }
-        return this;
-    }
-
-
-    /**
-     * Produce a string in double quotes with backslash sequences in all the
-     * right places. A backslash will be inserted within &lt;/, allowing JSON
-     * text to be delivered in HTML. In JSON text, a string cannot contain a
-     * control character or an unescaped quote or backslash.
-     * @param string A String
-     * @return  A String correctly formatted for insertion in a JSON text.
-     */
-    public static String quote(String string) {
-        if (string == null || string.length() == 0) {
+    public static String quote(String data) {
+        if (data == null) {
             return "\"\"";
         }
-
-        char         b;
-        char         c = 0;
-        int          i;
-        int          len = string.length();
-        StringBuilder sb = new StringBuilder(len + 4);
-        String       t;
-
-        sb.append('"');
-        for (i = 0; i < len; i += 1) {
-            b = c;
-            c = string.charAt(i);
-            switch (c) {
-            case '\\':
-            case '"':
-                sb.append('\\');
-                sb.append(c);
-                break;
-            case '/':
-                if (b == '<') {
-                    sb.append('\\');
-                }
-                sb.append(c);
-                break;
-            case '\b':
-                sb.append("\\b");
-                break;
-            case '\t':
-                sb.append("\\t");
-                break;
-            case '\n':
-                sb.append("\\n");
-                break;
-            case '\f':
-                sb.append("\\f");
-                break;
-            case '\r':
-                sb.append("\\r");
-                break;
-            default:
-                if (c < ' ') {
-                    t = "000" + Integer.toHexString(c);
-                    sb.append("\\u" + t.substring(t.length() - 4));
-                } else {
-                    sb.append(c);
-                }
-            }
-        }
-        sb.append('"');
-        return sb.toString();
-    }
-
-    /**
-     * Remove a name and its value, if present.
-     * @param key The name to be removed.
-     * @return The value that was associated with the name,
-     * or null if there was no value.
-     */
-    public Object remove(String key) {
-        return this.myHashMap.remove(key);
-    }
-
-    /**
-     * Throw an exception if the object is an NaN or infinite number.
-     * @param o The object to test.
-     * @throws JSONException If o is a non-finite number. 
-     */
-    static void testValidity(Object o) throws JSONException {
-        if (o != null) {
-            if (o instanceof Double) {
-                if (((Double)o).isInfinite() || ((Double)o).isNaN()) {
-                    throw new JSONException(
-                        "JSON does not allow non-finite numbers");
-                }
-            } else if (o instanceof Float) {
-                if (((Float)o).isInfinite() || ((Float)o).isNaN()) {
-                    throw new JSONException(
-                        "JSON does not allow non-finite numbers.");
-                }
-            }
-        }
-    }
-    
-    
-    /**
-     * Produce a JSONArray containing the values of the members of this
-     * JSONObject.
-     * @param names A JSONArray containing a list of key strings. This
-     * determines the sequence of the values in the result.
-     * @return A JSONArray of values.
-     * @throws JSONException If any of the values are non-finite numbers.
-     */
-    public JSONArray toJSONArray(JSONArray names) throws JSONException {
-        if (names == null || names.length() == 0) {
-            return null;
-        }
-        JSONArray ja = new JSONArray();
-        for (int i = 0; i < names.length(); i += 1) {
-            ja.put(this.opt(names.getString(i)));
-        }
-        return ja;
-    }
-
-    /**
-     * Make an JSON text of this JSONObject. For compactness, no whitespace
-     * is added. If this would not result in a syntactically correct JSON text, 
-     * then null will be returned instead.
-     * <p>
-     * Warning: This method assumes that the data structure is acyclical.
-     *
-     * @return a printable, displayable, portable, transmittable
-     *  representation of the object, beginning
-     *  with <code>{</code>&nbsp;<small>(left brace)</small> and ending
-     *  with <code>}</code>&nbsp;<small>(right brace)</small>.
-     */
-    public String toString() {
         try {
-            Iterator     keys = keys();
-            StringBuilder sb = new StringBuilder("{");
-    
-            while (keys.hasNext()) {
-                if (sb.length() > 1) {
-                    sb.append(',');
-                }
-                Object o = keys.next();
-                sb.append(quote(o.toString()));
-                sb.append(':');
-                sb.append(valueToString(this.myHashMap.get(o)));
-            }
-            sb.append('}');
-            return sb.toString();
-        } catch (Exception e) {
-            return null;
+            JSONStringer stringer = new JSONStringer();
+            stringer.open(JSONStringer.Scope.NULL, "");
+            stringer.value(data);
+            stringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, "");
+            return stringer.toString();
+        } catch (JSONException e) {
+            throw new AssertionError();
         }
     }
-
-
-    /**
-     * Make a prettyprinted JSON text of this JSONObject.
-     * <p>
-     * Warning: This method assumes that the data structure is acyclical.
-     * @param indentFactor The number of spaces to add to each level of
-     *  indentation.
-     * @return a printable, displayable, portable, transmittable
-     *  representation of the object, beginning
-     *  with <code>{</code>&nbsp;<small>(left brace)</small> and ending
-     *  with <code>}</code>&nbsp;<small>(right brace)</small>.
-     * @throws JSONException If the object contains an invalid number.
-     */
-    public String toString(int indentFactor) throws JSONException {
-        return toString(indentFactor, 0);
-    }
-
-
-    /**
-     * Make a prettyprinted JSON text of this JSONObject.
-     * <p>
-     * Warning: This method assumes that the data structure is acyclical.
-     * @param indentFactor The number of spaces to add to each level of
-     *  indentation.
-     * @param indent The indentation of the top level.
-     * @return a printable, displayable, transmittable
-     *  representation of the object, beginning
-     *  with <code>{</code>&nbsp;<small>(left brace)</small> and ending
-     *  with <code>}</code>&nbsp;<small>(right brace)</small>.
-     * @throws JSONException If the object contains an invalid number.
-     */
-    String toString(int indentFactor, int indent) throws JSONException {
-        int          i;
-        int          n = length();
-        if (n == 0) {
-            return "{}";
-        }
-        Iterator     keys = keys();
-        StringBuilder sb = new StringBuilder("{");
-        int          newindent = indent + indentFactor;
-        Object       o;
-        if (n == 1) {
-            o = keys.next();
-            sb.append(quote(o.toString()));
-            sb.append(": ");
-            sb.append(valueToString(this.myHashMap.get(o), indentFactor, 
-                    indent));
-        } else {
-            while (keys.hasNext()) {
-                o = keys.next();
-                if (sb.length() > 1) {
-                    sb.append(",\n");
-                } else {
-                    sb.append('\n');
-                }
-                for (i = 0; i < newindent; i += 1) {
-                    sb.append(' ');
-                }
-                sb.append(quote(o.toString()));
-                sb.append(": ");
-                sb.append(valueToString(this.myHashMap.get(o), indentFactor,
-                        newindent));
-            }
-            if (sb.length() > 1) {
-                sb.append('\n');
-                for (i = 0; i < indent; i += 1) {
-                    sb.append(' ');
-                }
-            }
-        }
-        sb.append('}');
-        return sb.toString();
-    }
-
-
-    /**
-     * Make a JSON text of an object value.
-     * <p>
-     * Warning: This method assumes that the data structure is acyclical.
-     * @param value The value to be serialized.
-     * @return a printable, displayable, transmittable
-     *  representation of the object, beginning
-     *  with <code>{</code>&nbsp;<small>(left brace)</small> and ending
-     *  with <code>}</code>&nbsp;<small>(right brace)</small>.
-     * @throws JSONException If the value is or contains an invalid number.
-     */
-    static String valueToString(Object value) throws JSONException {
-        if (value == null || value.equals(null)) {
-            return "null";
-        }
-        if (value instanceof Number) {
-            return numberToString((Number) value);
-        }
-        if (value instanceof Boolean || value instanceof JSONObject ||
-                value instanceof JSONArray) {
-            return value.toString();
-        }
-        return quote(value.toString());
-    }
-
-
-    /**
-     * Make a prettyprinted JSON text of an object value.
-     * <p>
-     * Warning: This method assumes that the data structure is acyclical.
-     * @param value The value to be serialized.
-     * @param indentFactor The number of spaces to add to each level of
-     *  indentation.
-     * @param indent The indentation of the top level.
-     * @return a printable, displayable, transmittable
-     *  representation of the object, beginning
-     *  with <code>{</code>&nbsp;<small>(left brace)</small> and ending
-     *  with <code>}</code>&nbsp;<small>(right brace)</small>.
-     * @throws JSONException If the object contains an invalid number.
-     */
-     static String valueToString(Object value, int indentFactor, int indent) 
-             throws JSONException {
-        if (value == null || value.equals(null)) {
-            return "null";
-        }
-        if (value instanceof Number) {
-            return numberToString((Number) value);
-        }
-        if (value instanceof Boolean) {
-            return value.toString();
-        }
-        if (value instanceof JSONObject) {
-            return ((JSONObject)value).toString(indentFactor, indent);
-        }
-        if (value instanceof JSONArray) {
-            return ((JSONArray)value).toString(indentFactor, indent);
-        }
-        return quote(value.toString());
-    }
 }
diff --git a/libcore/json/src/main/java/org/json/JSONStringer.java b/libcore/json/src/main/java/org/json/JSONStringer.java
index 1154823..fb60bd1 100644
--- a/libcore/json/src/main/java/org/json/JSONStringer.java
+++ b/libcore/json/src/main/java/org/json/JSONStringer.java
@@ -1,327 +1,340 @@
+/*
+ * 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 org.json;
 
-/*
-Copyright (c) 2005 JSON.org
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-The Software shall be used for Good, not Evil.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
+// Note: this class was written without inspecting the non-free org.json sourcecode.
 
 /**
- * JSONStringer provides a quick and convenient way of producing JSON text.
- * The texts produced strictly conform to JSON syntax rules. No whitespace is 
- * added, so the results are ready for transmission or storage. Each instance of 
- * JSONStringer can produce one JSON text.
- * <p>
- * A JSONStringer instance provides a <code>value</code> method for appending 
- * values to the 
- * text, and a <code>key</code> 
- * method for adding keys before values in objects. There are <code>array</code>
- * and <code>endArray</code> methods that make and bound array values, and 
- * <code>object</code> and <code>endObject</code> methods which make and bound 
- * object values. All of these methods return the JSONStringer instance, 
- * permitting cascade style. For example, <pre>
- * myString = new JSONStringer()
- *     .object()
- *         .key("JSON").value("Hello, World!")
- *     .endObject()
- *     .toString();</pre> which produces the string <pre>
- * {"JSON":"Hello, World!"}</pre>
- * <p>
- * The first method called must be <code>array</code> or <code>object</code>. 
- * There are no methods for adding commas or colons. JSONStringer adds them for 
- * you. Objects and arrays can be nested up to 20 levels deep.
- * <p>
- * This can sometimes be easier than using a JSONObject to build a string.
- * @author JSON.org
- * @version 2
+ *
  */
 public class JSONStringer {
-    private static final int maxdepth = 20;
-    
+
+    /** The output data, containing at most one top-level array or object. */
+    final StringBuilder out = new StringBuilder();
+
     /**
-     * The comma flag determines if a comma should be output before the next
-     * value.
+     * Lexical scoping elements within this stringer, necessary to insert the
+     * appropriate separator characters (ie. commas and colons) and to detect
+     * nesting errors.
      */
-    private boolean comma;
-    
-    /**
-     * The current mode. Values: 
-     * 'a' (array), 
-     * 'd' (done), 
-     * 'i' (initial), 
-     * 'k' (key), 
-     * 'o' (object).
-     */
-    private char mode;
-    
-    /**
-     * The string buffer that holds the JSON text that is built.
-     */
-    private StringBuilder sb;
-    
-    /**
-     * The object/array stack.
-     */
-    private char stack[];
-    
-    /**
-     * The stack top index. A value of 0 indicates that the stack is empty.
-     */
-    private int top;
-    
-    /**
-     * Make a fresh JSONStringer. It can be used to build one JSON text.
-     */
-    public JSONStringer() {
-        this.sb = new StringBuilder();
-        this.stack = new char[maxdepth];
-        this.top = 0;
-        this.mode = 'i';
-        this.comma = false;
-    }
-    
-    /**
-     * Append a value.
-     * @param s A string value.
-     * @return this
-     * @throws JSONException If the value is out of sequence.
-     */
-    private JSONStringer append(String s) 
-            throws JSONException {
-        if (s == null) {
-            throw new JSONException("Null pointer");
-        }
-        if (this.mode == 'o' || this.mode == 'a') {
-            if (this.comma && this.mode == 'a') {
-                this.sb.append(',');
-            }
-            this.sb.append(s);
-            if (this.mode == 'o') {
-                this.mode = 'k';
-            }
-            this.comma = true;
-            return this;
-        } 
-        throw new JSONException("Value out of sequence.");    
-    }
-    
-    /**
-     * Begin appending a new array. All values until the balancing 
-     * <code>endArray</code> will be appended to this array. The 
-     * <code>endArray</code> method must be called to mark the array's end.
-     * @return this
-     * @throws JSONException If the nesting is too deep, or if the object is 
-     * started in the wrong place (for example as a key or after the end of the 
-     * outermost array or object).
-     */
-    public JSONStringer array() throws JSONException {
-        if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
-            push('a');
-            this.append("[");
-            this.comma = false;
-            return this;
-        } 
-        throw new JSONException("Misplaced array.");
-    }
-    
-    /**
-     * End something. 
-     * @param m Mode
-     * @param c Closing character
-     * @return this
-     * @throws JSONException If unbalanced.
-     */
-    private JSONStringer end(char m, char c) throws JSONException {
-        if (this.mode != m) {
-            throw new JSONException(m == 'o' ? "Misplaced endObject." :
-                "Misplaced endArray.");            
-        }
-        pop(m);
-        this.sb.append(c);
-        this.comma = true;
-        return this;
-    }
-    
-    /**
-     * End an array. This method most be called to balance calls to 
-     * <code>array</code>.
-     * @return this
-     * @throws JSONException If incorrectly nested.
-     */
-    public JSONStringer endArray() throws JSONException {
-        return end('a', ']');
-    }
-    
-    /**
-     * End an object. This method most be called to balance calls to 
-     * <code>object</code>.
-     * @return this
-     * @throws JSONException If incorrectly nested.
-     */
-    public JSONStringer endObject() throws JSONException {
-        return end('k', '}');
-    }
-    
-    /**
-     * Append a key. The key will be associated with the next value. In an
-     * object, every value must be preceded by a key.
-     * @param s A key string.
-     * @return this
-     * @throws JSONException If the key is out of place. For example, keys
-     *     do not belong in arrays or if the key is null.
-     */
-    public JSONStringer key(String s) 
-            throws JSONException {
-        if (s == null) {
-            throw new JSONException("Null key.");
-        }
-        if (this.mode == 'k') {
-            if (this.comma) {
-                this.sb.append(',');
-            }
-            this.sb.append(JSONObject.quote(s));
-            this.sb.append(':');
-            this.comma = false;
-            this.mode = 'o';
-            return this;
-        } 
-        throw new JSONException("Misplaced key.");    
+    enum Scope {
+
+        /**
+         * An array with no elements requires no separators or newlines before
+         * it is closed.
+         */
+        EMPTY_ARRAY,
+
+        /**
+         * A array with at least one value requires a comma and newline before
+         * the next element.
+         */
+        NONEMPTY_ARRAY,
+
+        /**
+         * An object with no keys or values requires no separators or newlines
+         * before it is closed.
+         */
+        EMPTY_OBJECT,
+
+        /**
+         * An object whose most recent element is a key. The next element must
+         * be a value.
+         */
+        DANGLING_KEY,
+
+        /**
+         * An object with at least one name/value pair requires a comma and
+         * newline before the next element.
+         */
+        NONEMPTY_OBJECT,
+
+        /**
+         * A special bracketless array needed by JSONStringer.join() and
+         * JSONObject.quote() only. Not used for JSON encoding.
+         */
+        NULL,
     }
 
-    
     /**
-     * Begin appending a new object. All keys and values until the balancing 
-     * <code>endObject</code> will be appended to this object. The 
-     * <code>endObject</code> method must be called to mark the object's end.
-     * @return this
-     * @throws JSONException If the nesting is too deep, or if the object is 
-     * started in the wrong place (for example as a key or after the end of the 
-     * outermost array or object).
+     * Unlike the original implementation, this stack isn't limited to 20
+     * levels of nesting.
      */
+    private final List<Scope> stack = new ArrayList<Scope>();
+
+    /**
+     * A string containing a full set of spaces for a single level of
+     * indentation, or null for no pretty printing.
+     */
+    private final String indent;
+
+    public JSONStringer() {
+        indent = null;
+    }
+
+    JSONStringer(int indentSpaces) {
+        char[] indentChars = new char[indentSpaces];
+        Arrays.fill(indentChars, ' ');
+        indent = new String(indentChars);
+    }
+
+    public JSONStringer array() throws JSONException {
+        return open(Scope.EMPTY_ARRAY, "[");
+    }
+
+    public JSONStringer endArray() throws JSONException {
+        return close(Scope.EMPTY_ARRAY, Scope.NONEMPTY_ARRAY, "]");
+    }
+
     public JSONStringer object() throws JSONException {
-        if (this.mode == 'i') {
-            this.mode = 'o';
+        return open(Scope.EMPTY_OBJECT, "{");
+    }
+
+    public JSONStringer endObject() throws JSONException {
+        return close(Scope.EMPTY_OBJECT, Scope.NONEMPTY_OBJECT, "}");
+    }
+
+    /**
+     * Enters a new scope by appending any necessary whitespace and the given
+     * bracket.
+     */
+    JSONStringer open(Scope empty, String openBracket) throws JSONException {
+        if (stack.isEmpty() && out.length() > 0) {
+            throw new JSONException("Nesting problem: multiple top-level roots");
         }
-        if (this.mode == 'o' || this.mode == 'a') {
-            this.append("{");
-            push('k');
-            this.comma = false;
+        beforeValue();
+        stack.add(empty);
+        out.append(openBracket);
+        return this;
+    }
+
+    /**
+     * Closes the current scope by appending any necessary whitespace and the
+     * given bracket.
+     */
+    JSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException {
+        Scope context = peek();
+        if (context != nonempty && context != empty) {
+            throw new JSONException("Nesting problem");
+        }
+
+        stack.remove(stack.size() - 1);
+        if (context == nonempty) {
+            newline();
+        }
+        out.append(closeBracket);
+        return this;
+    }
+
+    /**
+     * Returns the value on the top of the stack.
+     */
+    private Scope peek() throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+        return stack.get(stack.size() - 1);
+    }
+
+    /**
+     * Replace the value on the top of the stack with the given value.
+     */
+    private void replaceTop(Scope topOfStack) {
+        stack.set(stack.size() - 1, topOfStack);
+    }
+
+    public JSONStringer value(Object value) throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+
+        if (value instanceof JSONArray) {
+            ((JSONArray) value).writeTo(this);
             return this;
-        } 
-        throw new JSONException("Misplaced object.");
-        
-    }
-    
-    
-    /**
-     * Pop an array or object scope.
-     * @param c The scope to close.
-     * @throws JSONException If nesting is wrong.
-     */
-    private void pop(char c) throws JSONException {
-        if (this.top <= 0 || this.stack[this.top - 1] != c) {
-            throw new JSONException("Nesting error.");
+
+        } else if (value instanceof JSONObject) {
+            ((JSONObject) value).writeTo(this);
+            return this;
         }
-        this.top -= 1;
-        this.mode = this.top == 0 ? 'd' : this.stack[this.top - 1];
-    }
-    
-    /**
-     * Push an array or object scope.
-     * @param c The scope to open.
-     * @throws JSONException If nesting is too deep.
-     */
-    private void push(char c) throws JSONException {
-        if (this.top >= maxdepth) {
-            throw new JSONException("Nesting too deep.");
+
+        beforeValue();
+
+        if (value == null
+                || value instanceof Boolean
+                || value == JSONObject.NULL) {
+            out.append(value);
+
+        } else if (value instanceof Number) {
+            out.append(JSONObject.numberToString((Number) value));
+
+        } else {
+            string(value.toString());
         }
-        this.stack[this.top] = c;
-        this.mode = c;
-        this.top += 1;
+
+        return this;
     }
-    
-    
-    /**
-     * Append either the value <code>true</code> or the value 
-     * <code>false</code>. 
-     * @param b A boolean.
-     * @return this
-     * @throws JSONException
-     */
-    public JSONStringer value(boolean b) throws JSONException {
-        return this.append(b ? "true" : "false");
-    }
-    
-    /**
-     * Append a double value.
-     * @param d A double.
-     * @return this
-     * @throws JSONException If the number is not finite.
-     */
-    public JSONStringer value(double d) throws JSONException {
-        return this.value(new Double(d));
-    }
-    
-    /**
-     * Append a long value.
-     * @param l A long.
-     * @return this
-     * @throws JSONException
-     */
-    public JSONStringer value(long l) throws JSONException {
-        return this.append(Long.toString(l));
-    }
-    
-    
-    /**
-     * Append an object value.
-     * @param o The object to append. It can be null, or a Boolean, Number,
-     *   String, JSONObject, or JSONArray.
-     * @return this
-     * @throws JSONException If the value is out of sequence.
-     */
-    public JSONStringer value(Object o) throws JSONException {
-        if (JSONObject.NULL.equals(o)) {
-            return this.append("null");
+
+    public JSONStringer value(boolean value) throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
         }
-        if (o instanceof Number) {
-            JSONObject.testValidity(o);
-            return this.append(JSONObject.numberToString((Number)o));
-        }
-        if (o instanceof Boolean || 
-                o instanceof JSONArray || o instanceof JSONObject) {
-            return this.append(o.toString());
-        }
-        return this.append(JSONObject.quote(o.toString()));
+        beforeValue();
+        out.append(value);
+        return this;
     }
-    
+
+    public JSONStringer value(double value) throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+        beforeValue();
+        out.append(JSONObject.numberToString(value));
+        return this;
+    }
+
+    public JSONStringer value(long value) throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+        beforeValue();
+        out.append(value);
+        return this;
+    }
+
+    private void string(String value) {
+        out.append("\"");
+        for (int i = 0, length = value.length(); i < length; i++) {
+            char c = value.charAt(i);
+
+            /*
+             * From RFC 4627, "All Unicode characters may be placed within the
+             * quotation marks except for the characters that must be escaped:
+             * quotation mark, reverse solidus, and the control characters
+             * (U+0000 through U+001F)."
+             */
+            switch (c) {
+                case '"':
+                case '\\':
+                case '/':
+                    out.append('\\').append(c);
+                    break;
+
+                case '\t':
+                    out.append("\\t");
+                    break;
+
+                case '\b':
+                    out.append("\\b");
+                    break;
+
+                case '\n':
+                    out.append("\\n");
+                    break;
+
+                case '\r':
+                    out.append("\\r");
+                    break;
+
+                case '\f':
+                    out.append("\\f");
+                    break;
+
+                default:
+                    if (c <= 0x1F) {
+                        out.append(String.format("\\u%04x", (int) c));
+                    } else {
+                        out.append(c);
+                    }
+                    break;
+            }
+
+        }
+        out.append("\"");
+    }
+
+    private void newline() {
+        if (indent == null) {
+            return;
+        }
+
+        out.append("\n");
+        for (int i = 0; i < stack.size(); i++) {
+            out.append(indent);
+        }
+    }
+
+    public JSONStringer key(String name) throws JSONException {
+        if (name == null) {
+            throw new JSONException("Names must be non-null");
+        }
+        beforeKey();
+        string(name);
+        return this;
+    }
+
     /**
-     * Return the JSON text. This method is used to obtain the product of the
-     * JSONStringer instance. It will return <code>null</code> if there was a 
-     * problem in the construction of the JSON text (such as the calls to 
-     * <code>array</code> were not properly balanced with calls to 
-     * <code>endArray</code>).
-     * @return The JSON text.
+     * Inserts any necessary separators and whitespace before a name. Also
+     * adjusts the stack to expect the key's value.
      */
-    public String toString() {
-        return this.mode == 'd' ? this.sb.toString() : null;
+    private void beforeKey() throws JSONException {
+        Scope context = peek();
+        if (context == Scope.NONEMPTY_OBJECT) { // first in object
+            out.append(',');
+        } else if (context != Scope.EMPTY_OBJECT) { // not in an object!
+            throw new JSONException("Nesting problem");
+        }
+        newline();
+        replaceTop(Scope.DANGLING_KEY);
+    }
+
+    /**
+     * Inserts any necessary separators and whitespace before a literal value,
+     * inline array, or inline object. Also adjusts the stack to expect either a
+     * closing bracket or another element.
+     */
+    private void beforeValue() throws JSONException {
+        if (stack.isEmpty()) {
+            return;
+        }
+
+        Scope context = peek();
+        if (context == Scope.EMPTY_ARRAY) { // first in array
+            replaceTop(Scope.NONEMPTY_ARRAY);
+            newline();
+        } else if (context == Scope.NONEMPTY_ARRAY) { // another in array
+            out.append(',');
+            newline();
+        } else if (context == Scope.DANGLING_KEY) { // value for key
+            out.append(indent == null ? ":" : ": ");
+            replaceTop(Scope.NONEMPTY_OBJECT);
+        } else if (context != Scope.NULL) {
+            throw new JSONException("Nesting problem");
+        }
+    }
+
+    /**
+     * Although it contradicts the general contract of {@link Object#toString},
+     * this method returns null if the stringer contains no data.
+     */
+    @Override public String toString() {
+        return out.length() == 0 ? null : out.toString();
     }
 }
diff --git a/libcore/json/src/main/java/org/json/JSONTokener.java b/libcore/json/src/main/java/org/json/JSONTokener.java
index 7ac1cd7..e249c74 100644
--- a/libcore/json/src/main/java/org/json/JSONTokener.java
+++ b/libcore/json/src/main/java/org/json/JSONTokener.java
@@ -1,460 +1,480 @@
+/*
+ * 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 org.json;
 
-/*
-Copyright (c) 2002 JSON.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-The Software shall be used for Good, not Evil.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
+// Note: this class was written without inspecting the non-free org.json sourcecode.
 
 /**
- * A JSONTokener takes a source string and extracts characters and tokens from
- * it. It is used by the JSONObject and JSONArray constructors to parse
- * JSON source strings.
- * @author JSON.org
- * @version 2
+ *
  */
 public class JSONTokener {
 
-    /**
-     * The index of the next character.
-     */
-    private int myIndex;
-
+    /** The input JSON. */
+    private final String in;
 
     /**
-     * The source string being tokenized.
+     * The index of the next character to be returned by {@link #next()}. When
+     * the input is exhausted, this equals the input's length.
      */
-    private String mySource;
+    private int pos;
 
-
-    /**
-     * Construct a JSONTokener from a string.
-     *
-     * @param s     A source string.
-     */
-    public JSONTokener(String s) {
-        this.myIndex = 0;
-        this.mySource = s;
+    public JSONTokener(String in) {
+        this.in = in;
     }
 
+    public Object nextValue() throws JSONException {
+        int c = nextCleanInternal();
+        switch (c) {
+            case -1:
+                throw syntaxError("End of input");
 
-    /**
-     * Back up one character. This provides a sort of lookahead capability,
-     * so that you can test for a digit or letter before attempting to parse
-     * the next number or identifier.
-     */
-    public void back() {
-        if (this.myIndex > 0) {
-            this.myIndex -= 1;
+            case '{':
+                return readObject();
+
+            case '[':
+                return readArray();
+
+            case '\'':
+            case '"':
+                return nextString((char) c);
+
+            default:
+                pos--;
+                return readLiteral();
         }
     }
 
+    private int nextCleanInternal() throws JSONException {
+        while (pos < in.length()) {
+            int c = in.charAt(pos++);
+            switch (c) {
+                case '\t':
+                case ' ':
+                case '\n':
+                case '\r':
+                    continue;
 
+                case '/':
+                    if (pos == in.length()) {
+                        return c;
+                    }
 
-    /**
-     * Get the hex value of a character (base16).
-     * @param c A character between '0' and '9' or between 'A' and 'F' or
-     * between 'a' and 'f'.
-     * @return  An int between 0 and 15, or -1 if c was not a hex digit.
-     */
-    public static int dehexchar(char c) {
-        if (c >= '0' && c <= '9') {
-            return c - '0';
+                    char peek = in.charAt(pos);
+                    if (peek != '*' && peek != '/') {
+                        return c;
+                    }
+
+                    skipComment();
+                    continue;
+
+                default:
+                    return c;
+            }
         }
-        if (c >= 'A' && c <= 'F') {
-            return c - ('A' - 10);
-        }
-        if (c >= 'a' && c <= 'f') {
-            return c - ('a' - 10);
-        }
+
         return -1;
     }
 
-
     /**
-     * Determine if the source string still contains characters that next()
-     * can consume.
-     * @return true if not yet at the end of the source.
-     */
-    public boolean more() {
-        return this.myIndex < this.mySource.length();
-    }
-
-
-    /**
-     * Get the next character in the source string.
+     * Advances the position until it is beyond the current comment. The opening
+     * slash '/' should have already been read, and character at the current
+     * position be an asterisk '*' for a C-style comment or a slash '/' for an
+     * end-of-line comment.
      *
-     * @return The next character, or 0 if past the end of the source string.
+     * @throws JSONException if a C-style comment was not terminated.
      */
-    public char next() {
-        if (more()) {
-            char c = this.mySource.charAt(this.myIndex);
-            this.myIndex += 1;
-            return c;
-        }
-        return 0;
-    }
+    private void skipComment() throws JSONException {
+        if (in.charAt(pos++) == '*') {
+            int commentEnd = in.indexOf("*/", pos);
+            if (commentEnd == -1) {
+                throw syntaxError("Unterminated comment");
+            }
+            pos = commentEnd + 2;
 
-
-    /**
-     * Consume the next character, and check that it matches a specified
-     * character.
-     * @param c The character to match.
-     * @return The character.
-     * @throws JSONException if the character does not match.
-     */
-    public char next(char c) throws JSONException {
-        char n = next();
-        if (n != c) {
-            throw syntaxError("Expected '" + c + "' and instead saw '" +
-                    n + "'.");
-        }
-        return n;
-    }
-
-
-    /**
-     * Get the next n characters.
-     *
-     * @param n     The number of characters to take.
-     * @return      A string of n characters.
-     * @throws JSONException
-     *   Substring bounds error if there are not
-     *   n characters remaining in the source string.
-     */
-     public String next(int n) throws JSONException {
-         int i = this.myIndex;
-         int j = i + n;
-         if (j >= this.mySource.length()) {
-            throw syntaxError("Substring bounds error");
-         }
-         this.myIndex += n;
-         return this.mySource.substring(i, j);
-     }
-
-
-    /**
-     * Get the next char in the string, skipping whitespace
-     * and comments (slashslash, slashstar, and hash).
-     * @throws JSONException
-     * @return  A character, or 0 if there are no more characters.
-     */
-    public char nextClean() throws JSONException {
-        for (;;) {
-            char c = next();
-            if (c == '/') {
-                switch (next()) {
-                case '/':
-                    do {
-                        c = next();
-                    } while (c != '\n' && c != '\r' && c != 0);
+        } else {
+            /*
+             * Skip to the next newline character. If the line is terminated by
+             * "\r\n", the '\n' will be consumed as whitespace by the caller.
+             */
+            for (; pos < in.length(); pos++) {
+                char c = in.charAt(pos);
+                if (c == '\r' || c == '\n') {
+                    pos++;
                     break;
-                case '*':
-                    for (;;) {
-                        c = next();
-                        if (c == 0) {
-                            throw syntaxError("Unclosed comment.");
-                        }
-                        if (c == '*') {
-                            if (next() == '/') {
-                                break;
-                            }
-                            back();
-                        }
-                    }
-                    break;
-                default:
-                    back();
-                    return '/';
                 }
-            } else if (c == '#') {
-                do {
-                    c = next();
-                } while (c != '\n' && c != '\r' && c != 0);
-            } else if (c == 0 || c > ' ') {
-                return c;
             }
         }
     }
 
-
     /**
-     * Return the characters up to the next close quote character.
-     * Backslash processing is done. The formal JSON format does not
-     * allow strings in single quotes, but an implementation is allowed to
-     * accept them.
-     * @param quote The quoting character, either
-     *      <code>"</code>&nbsp;<small>(double quote)</small> or
-     *      <code>'</code>&nbsp;<small>(single quote)</small>.
-     * @return      A String.
-     * @throws JSONException Unterminated string.
+     *
+     *
+     * @throws NumberFormatException if any unicode escape sequences are
+     *     malformed.
      */
     public String nextString(char quote) throws JSONException {
-        char c;
-        StringBuilder sb = new StringBuilder();
-        for (;;) {
-            c = next();
-            switch (c) {
-            case 0:
-            case '\n':
-            case '\r':
-                throw syntaxError("Unterminated string");
-            case '\\':
-                c = next();
-                switch (c) {
-                case 'b':
-                    sb.append('\b');
-                    break;
-                case 't':
-                    sb.append('\t');
-                    break;
-                case 'n':
-                    sb.append('\n');
-                    break;
-                case 'f':
-                    sb.append('\f');
-                    break;
-                case 'r':
-                    sb.append('\r');
-                    break;
-                case 'u':
-                    sb.append((char)Integer.parseInt(next(4), 16));
-                    break;
-                case 'x' :
-                    sb.append((char) Integer.parseInt(next(2), 16));
-                    break;
-                default:
-                    sb.append(c);
+        /*
+         * For strings that are free of escape sequences, we can just extract
+         * the result as a substring of the input. But if we encounter an escape
+         * sequence, we need to use a StringBuilder to compose the result.
+         */
+        StringBuilder builder = null;
+
+        /* the index of the first character not yet appended to the builder. */
+        int start = pos;
+
+        while (pos < in.length()) {
+            int c = in.charAt(pos++);
+            if (c == quote) {
+                if (builder == null) {
+                    // a new string avoids leaking memory
+                    return new String(in.substring(start, pos - 1));
+                } else {
+                    builder.append(in, start, pos - 1);
+                    return builder.toString();
                 }
-                break;
-            default:
-                if (c == quote) {
-                    return sb.toString();
+            }
+
+            if (c == '\\') {
+                if (pos == in.length()) {
+                    throw syntaxError("Unterminated escape sequence");
                 }
-                sb.append(c);
+                if (builder == null) {
+                    builder = new StringBuilder();
+                }
+                builder.append(in, start, pos - 1);
+                builder.append(readEscapeCharacter());
+                start = pos;
             }
         }
+
+        throw syntaxError("Unterminated string");
     }
 
-
     /**
-     * Get the text up but not including the specified character or the
-     * end of line, whichever comes first.
-     * @param  d A delimiter character.
-     * @return   A string.
-     */
-    public String nextTo(char d) {
-        StringBuilder sb = new StringBuilder();
-        for (;;) {
-            char c = next();
-            if (c == d || c == 0 || c == '\n' || c == '\r') {
-                if (c != 0) {
-                    back();
-                }
-                return sb.toString().trim();
-            }
-            sb.append(c);
-        }
-    }
-
-
-    /**
-     * Get the text up but not including one of the specified delimeter
-     * characters or the end of line, whichever comes first.
-     * @param delimiters A set of delimiter characters.
-     * @return A string, trimmed.
-     */
-    public String nextTo(String delimiters) {
-        char c;
-        StringBuilder sb = new StringBuilder();
-        for (;;) {
-            c = next();
-            if (delimiters.indexOf(c) >= 0 || c == 0 ||
-                    c == '\n' || c == '\r') {
-                if (c != 0) {
-                    back();
-                }
-                return sb.toString().trim();
-            }
-            sb.append(c);
-        }
-    }
-
-
-    /**
-     * Get the next value. The value can be a Boolean, Double, Integer,
-     * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
-     * @throws JSONException If syntax error.
+     * Unescapes the character identified by the character or characters that
+     * immediately follow a backslash. The backslash '\' should have already
+     * been read. This supports both unicode escapes "u000A" and two-character
+     * escapes "\n".
      *
-     * @return An object.
+     * @throws NumberFormatException if any unicode escape sequences are
+     *     malformed.
      */
-    public Object nextValue() throws JSONException {
-        char c = nextClean();
-        String s;
+    private char readEscapeCharacter() throws JSONException {
+        char escaped = in.charAt(pos++);
+        switch (escaped) {
+            case 'u':
+                if (pos + 4 > in.length()) {
+                    throw syntaxError("Unterminated escape sequence");
+                }
+                String hex = in.substring(pos, pos + 4);
+                pos += 4;
+                return (char) Integer.parseInt(hex, 16);
 
-        switch (c) {
-            case '"':
+            case 't':
+                return '\t';
+
+            case 'b':
+                return '\b';
+
+            case 'n':
+                return '\n';
+
+            case 'r':
+                return '\r';
+
+            case 'f':
+                return '\f';
+
             case '\'':
-                return nextString(c);
-            case '{':
-                back();
-                return new JSONObject(this);
-            case '[':
-                back();
-                return new JSONArray(this);
+            case '"':
+            case '\\':
+            default:
+                return escaped;
         }
+    }
 
-        /*
-         * Handle unquoted text. This could be the values true, false, or
-         * null, or it can be a number. An implementation (such as this one)
-         * is allowed to also accept non-standard forms.
-         *
-         * Accumulate characters until we reach the end of the text or a
-         * formatting character.
-         */
+    /**
+     * Reads a null, boolean, numeric or unquoted string literal value. Numeric
+     * values will be returned as an Integer, Long, or Double, in that order of
+     * preference.
+     */
+    private Object readLiteral() throws JSONException {
+        String literal = nextToInternal("{}[]/\\:,=;# \t\f");
 
-        StringBuilder sb = new StringBuilder();
-        char b = c;
-        while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
-            sb.append(c);
-            c = next();
-        }
-        back();
-
-        /*
-         * If it is true, false, or null, return the proper value.
-         */
-
-        s = sb.toString().trim();
-        if (s.equals("")) {
-            throw syntaxError("Missing value.");
-        }
-        if (s.equalsIgnoreCase("true")) {
+        if (literal.length() == 0) {
+            throw syntaxError("Expected literal value");
+        } else if ("null".equalsIgnoreCase(literal)) {
+            return JSONObject.NULL;
+        } else if ("true".equalsIgnoreCase(literal)) {
             return Boolean.TRUE;
-        }
-        if (s.equalsIgnoreCase("false")) {
+        } else if ("false".equalsIgnoreCase(literal)) {
             return Boolean.FALSE;
         }
-        if (s.equalsIgnoreCase("null")) {
-            return JSONObject.NULL;
-        }
 
-        /*
-         * If it might be a number, try converting it. We support the 0- and 0x-
-         * conventions. If a number cannot be produced, then the value will just
-         * be a string. Note that the 0-, 0x-, plus, and implied string
-         * conventions are non-standard. A JSON parser is free to accept
-         * non-JSON forms as long as it accepts all correct JSON forms.
-         */
-
-        if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') {
-            if (b == '0') {
-                if (s.length() > 2 &&
-                        (s.charAt(1) == 'x' || s.charAt(1) == 'X')) {
-                    try {
-                        return new Integer(Integer.parseInt(s.substring(2), 
-                                16));
-                    } catch (Exception e) {
-                        /* Ignore the error */
-                    }
-                } else {
-                    try {
-                        return new Integer(Integer.parseInt(s, 8));
-                    } catch (Exception e) {
-                        /* Ignore the error */
-                    }
-                }
+        /* try to parse as an integral type... */
+        if (literal.indexOf('.') == -1) {
+            int base = 10;
+            String number = literal;
+            if (number.startsWith("0x") || number.startsWith("0X")) {
+                number = number.substring(2);
+                base = 16;
+            } else if (number.startsWith("0") && number.length() > 1) {
+                number = number.substring(1);
+                base = 8;
             }
             try {
-                return new Integer(s);
-            } catch (Exception e) {
-                try {
-                    return new Long(s);
-                } catch (Exception f) {
-                    try {
-                        return new Double(s);
-                    }  catch (Exception g) {
-                        return s;
-                    }
+                long longValue = Long.parseLong(number, base);
+                if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {
+                    return (int) longValue;
+                } else {
+                    return longValue;
+                }
+            } catch (NumberFormatException e) {
+                /*
+                 * This only happens for integral numbers greater than
+                 * Long.MAX_VALUE, numbers in exponential form (5e-10) and
+                 * unquoted strings. Fall through to try floating point.
+                 */
+            }
+        }
+
+        /* ...next try to parse as a floating point... */
+        try {
+            return Double.valueOf(literal);
+        } catch (NumberFormatException e) {
+        }
+
+        /* ... finally give up. We have an unquoted string */
+        return new String(literal); // a new string avoids leaking memory
+    }
+
+    /**
+     * Returns text from the current position until the first of any of the
+     * given characters or a newline character, excluding that character. The
+     * position is advanced to the excluded character.
+     */
+    private String nextToInternal(String excluded) {
+        int start = pos;
+        for (; pos < in.length(); pos++) {
+            char c = in.charAt(pos);
+            if (c == '\r' || c == '\n' || excluded.indexOf(c) != -1) {
+                return in.substring(start, pos);
+            }
+        }
+        return in.substring(start);
+    }
+
+    /**
+     * Reads a sequence of key/value pairs and the trailing closing brace '}' of
+     * an object. The opening brace '{' should have already been read.
+     */
+    private JSONObject readObject() throws JSONException {
+        JSONObject result = new JSONObject();
+
+        /* Peek to see if this is the empty object. */
+        int first = nextCleanInternal();
+        if (first == '}') {
+            return result;
+        } else if (first != -1) {
+            pos--;
+        }
+
+        while (true) {
+            Object name = nextValue();
+            if (!(name instanceof String)) {
+                if (name == null) {
+                    throw syntaxError("Names cannot be null");
+                } else {
+                    throw syntaxError("Names must be strings, but " + name
+                            + " is of type " + name.getClass().getName());
                 }
             }
-        }
-        return s;
-    }
 
-
-    /**
-     * Skip characters until the next character is the requested character.
-     * If the requested character is not found, no characters are skipped.
-     * @param to A character to skip to.
-     * @return The requested character, or zero if the requested character
-     * is not found.
-     */
-    public char skipTo(char to) {
-        char c;
-        int index = this.myIndex;
-        do {
-            c = next();
-            if (c == 0) {
-                this.myIndex = index;
-                return c;
+            /*
+             * Expect the name/value separator to be either a colon ':', an
+             * equals sign '=', or an arrow "=>". The last two are bogus but we
+             * include them because that's what the original implementation did.
+             */
+            int separator = nextCleanInternal();
+            if (separator != ':' && separator != '=') {
+                throw syntaxError("Expected ':' after " + name);
             }
-        } while (c != to);
-        back();
-        return c;
-    }
+            if (pos < in.length() && in.charAt(pos) == '>') {
+                pos++;
+            }
 
+            result.put((String) name, nextValue());
 
-    /**
-     * Skip characters until past the requested string.
-     * If it is not found, we are left at the end of the source.
-     * @param to A string to skip past.
-     */
-    public void skipPast(String to) {
-        this.myIndex = this.mySource.indexOf(to, this.myIndex);
-        if (this.myIndex < 0) {
-            this.myIndex = this.mySource.length();
-        } else {
-            this.myIndex += to.length();
+            switch (nextCleanInternal()) {
+                case '}':
+                    return result;
+                case ';':
+                case ',':
+                    continue;
+                default:
+                    throw syntaxError("Unterminated object");
+            }
         }
     }
 
-
     /**
-     * Make a JSONException to signal a syntax error.
-     *
-     * @param message The error message.
-     * @return  A JSONException object, suitable for throwing
+     * Reads a sequence of values and the trailing closing brace ']' of an
+     * array. The opening brace '[' should have already been read. Note that
+     * "[]" yields an empty array, but "[,]" returns a two-element array
+     * equivalent to "[null,null]".
      */
-    public JSONException syntaxError(String message) {
-        return new JSONException(message + toString());
+    private JSONArray readArray() throws JSONException {
+        JSONArray result = new JSONArray();
+
+        /* to cover input that ends with ",]". */
+        boolean hasTrailingSeparator = false;
+
+        while (true) {
+            switch (nextCleanInternal()) {
+                case -1:
+                    throw syntaxError("Unterminated array");
+                case ']':
+                    if (hasTrailingSeparator) {
+                        result.put(null);
+                    }
+                    return result;
+                case ',':
+                case ';':
+                    /* A separator without a value first means "null". */
+                    result.put(null);
+                    hasTrailingSeparator = true;
+                    continue;
+                default:
+                    pos--;
+            }
+
+            result.put(nextValue());
+
+            switch (nextCleanInternal()) {
+                case ']':
+                    return result;
+                case ',':
+                case ';':
+                    hasTrailingSeparator = true;
+                    continue;
+                default:
+                    throw syntaxError("Unterminated array");
+            }
+        }
     }
 
+    public JSONException syntaxError(String text) {
+        return new JSONException(text + this);
+    }
+
+    @Override public String toString() {
+        // consistent with the original implementation
+        return " at character " + pos + " of " + in;
+    }
+
+    /*
+     * Legacy APIs.
+     *
+     * None of the methods below are on the critical path of parsing JSON
+     * documents. They exist only because they were exposed by the original
+     * implementation and may be used by some clients.
+     */
+
+    public boolean more() {
+        return pos < in.length();
+    }
+
+    public char next() {
+        return pos < in.length() ? in.charAt(pos++) : '\0';
+    }
+
+    public char next(char c) throws JSONException {
+        char result = next();
+        if (result != c) {
+            throw syntaxError("Expected " + c + " but was " + result);
+        }
+        return result;
+    }
+
+    public char nextClean() throws JSONException {
+        int nextCleanInt = nextCleanInternal();
+        return nextCleanInt == -1 ? '\0' : (char) nextCleanInt;
+    }
 
     /**
-     * Make a printable string of this JSONTokener.
-     *
-     * @return " at character [this.myIndex] of [this.mySource]"
+     * TODO: note about how this method returns a substring, and could cause a memory leak
      */
-    public String toString() {
-        return " at character " + this.myIndex + " of " + this.mySource;
-    }   
-}
\ No newline at end of file
+    public String next(int length) throws JSONException {
+        if (pos + length > in.length()) {
+            throw syntaxError(length + " is out of bounds");
+        }
+        String result = in.substring(pos, pos + length);
+        pos += length;
+        return result;
+    }
+
+    /**
+     * TODO: note about how this method returns a substring, and could cause a memory leak
+     */
+    public String nextTo(String excluded) {
+        if (excluded == null) {
+            throw new NullPointerException();
+        }
+        return nextToInternal(excluded).trim();
+    }
+
+    /**
+     * TODO: note about how this method returns a substring, and could cause a memory leak
+     */
+    public String nextTo(char excluded) {
+        return nextToInternal(String.valueOf(excluded)).trim();
+    }
+
+    public void skipPast(String thru) {
+        int thruStart = in.indexOf(thru, pos);
+        pos = thruStart == -1 ? in.length() : (thruStart + thru.length());
+    }
+
+    public char skipTo(char to) {
+        for (int i = pos, length = in.length(); i < length; i++) {
+            if (in.charAt(i) == to) {
+                pos = i;
+                return to;
+            }
+        }
+        return '\0';
+    }
+
+    public void back() {
+        if (--pos == -1) {
+            pos = 0;
+        }
+    }
+
+    public static int dehexchar(char hex) {
+        if (hex >= '0' && hex <= '9') {
+            return hex - '0';
+        } else if (hex >= 'A' && hex <= 'F') {
+            return hex - 'A' + 10;
+        } else if (hex >= 'a' && hex <= 'f') {
+            return hex - 'a' + 10;
+        } else {
+            return -1;
+        }
+    }
+}
diff --git a/libcore/json/src/test/java/org/json/AllTests.java b/libcore/json/src/test/java/org/json/AllTests.java
index 7779c91..8f5cc94 100644
--- a/libcore/json/src/test/java/org/json/AllTests.java
+++ b/libcore/json/src/test/java/org/json/AllTests.java
@@ -23,8 +23,11 @@
     public static Test suite() {
         TestSuite suite = new TestSuite();
         suite.addTestSuite(JSONArrayTest.class);
+        suite.addTestSuite(JSONObjectTest.class);
         suite.addTestSuite(JSONStringerTest.class);
-        suite.addTestSuite(JSONStringerTest.class);
+        suite.addTestSuite(JSONTokenerTest.class);
+        suite.addTestSuite(ParsingTest.class);
+        suite.addTestSuite(SelfUseTest.class);
         return suite;
     }
 }
diff --git a/libcore/json/src/test/java/org/json/JSONArrayTest.java b/libcore/json/src/test/java/org/json/JSONArrayTest.java
index 34e5ff6..485a729 100644
--- a/libcore/json/src/test/java/org/json/JSONArrayTest.java
+++ b/libcore/json/src/test/java/org/json/JSONArrayTest.java
@@ -1,11 +1,11 @@
-/**
+/*
  * 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
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,6 +19,8 @@
 import junit.framework.TestCase;
 
 import java.util.Arrays;
+import java.util.List;
+import java.util.Collections;
 
 /**
  * This black box test was written without inspecting the non-free org.json sourcecode.
@@ -49,7 +51,7 @@
         assertFalse(array.optBoolean(0));
         assertTrue(array.optBoolean(0, true));
 
-        // bogus (but documented) behaviour: returns null rather than an empty object
+        // bogus (but documented) behaviour: returns null rather than an empty object!
         assertNull(array.toJSONObject(new JSONArray()));
     }
 
@@ -57,8 +59,7 @@
         JSONArray a = new JSONArray();
         JSONArray b = new JSONArray();
         assertTrue(a.equals(b));
-        // bogus behavior: JSONArray overrides equals() but not hashCode().
-        assertEquals(a.hashCode(), b.hashCode());
+        assertEquals("equals() not consistent with hashCode()", a.hashCode(), b.hashCode());
 
         a.put(true);
         a.put(false);
@@ -128,20 +129,20 @@
         assertEquals(4, array.length());
         assertEquals("[null,null,null,null]", array.toString());
 
-        // bogus behaviour: there's 2 ways to represent null; each behaves differently!
+        // there's 2 ways to represent null; each behaves differently!
         assertEquals(JSONObject.NULL, array.get(0));
         try {
-            assertEquals(null, array.get(1));
+            array.get(1);
             fail();
         } catch (JSONException e) {
         }
         try {
-            assertEquals(null, array.get(2));
+            array.get(2);
             fail();
         } catch (JSONException e) {
         }
         try {
-            assertEquals(null, array.get(3));
+            array.get(3);
             fail();
         } catch (JSONException e) {
         }
@@ -167,7 +168,7 @@
         array.put(-0d);
         assertEquals(4, array.length());
 
-        // bogus behaviour: toString() and getString(int) return different values for -0d
+        // toString() and getString(int) return different values for -0d
         assertEquals("[4.9E-324,9223372036854775806,1.7976931348623157E308,-0]", array.toString());
 
         assertEquals(Double.MIN_VALUE, array.get(0));
@@ -238,7 +239,7 @@
         assertEquals(-2, array.optInt(0, -2));
 
         assertEquals(5.5d, array.getDouble(1));
-        assertEquals(5, array.getLong(1));
+        assertEquals(5L, array.getLong(1));
         assertEquals(5, array.getInt(1));
         assertEquals(5, array.optInt(1, 3));
 
@@ -258,6 +259,32 @@
         assertEquals(-1.0d, array.optDouble(3, -1.0d));
     }
 
+    public void testJoin() throws JSONException {
+        JSONArray array = new JSONArray();
+        array.put(null);
+        assertEquals("null", array.join(" & "));
+        array.put("\"");
+        assertEquals("null & \"\\\"\"", array.join(" & "));
+        array.put(5);
+        assertEquals("null & \"\\\"\" & 5", array.join(" & "));
+        array.put(true);
+        assertEquals("null & \"\\\"\" & 5 & true", array.join(" & "));
+        array.put(new JSONArray(Arrays.asList(true, false)));
+        assertEquals("null & \"\\\"\" & 5 & true & [true,false]", array.join(" & "));
+        array.put(new JSONObject(Collections.singletonMap("x", 6)));
+        assertEquals("null & \"\\\"\" & 5 & true & [true,false] & {\"x\":6}", array.join(" & "));
+    }
+
+    public void testJoinWithNull() throws JSONException {
+        JSONArray array = new JSONArray(Arrays.asList(5, 6));
+        assertEquals("5null6", array.join(null));
+    }
+
+    public void testJoinWithSpecialCharacters() throws JSONException {
+        JSONArray array = new JSONArray(Arrays.asList(5, 6));
+        assertEquals("5\"6", array.join("\""));
+    }
+
     public void testToJSONObject() throws JSONException {
         JSONArray keys = new JSONArray();
         keys.put("a");
@@ -285,13 +312,45 @@
         values.put(5.5d);
         values.put(null);
 
-        // bogus behaviour: null values are stripped 
+        // null values are stripped!
         JSONObject object = values.toJSONObject(keys);
         assertEquals(1, object.length());
         assertFalse(object.has("b"));
         assertEquals("{\"a\":5.5}", object.toString());
     }
 
+    public void testToJSONObjectMoreNamesThanValues() throws JSONException {
+        JSONArray keys = new JSONArray();
+        keys.put("a");
+        keys.put("b");
+        JSONArray values = new JSONArray();
+        values.put(5.5d);
+        JSONObject object = values.toJSONObject(keys);
+        assertEquals(1, object.length());
+        assertEquals(5.5d, object.get("a"));
+    }
+
+    public void testToJSONObjectMoreValuesThanNames() throws JSONException {
+        JSONArray keys = new JSONArray();
+        keys.put("a");
+        JSONArray values = new JSONArray();
+        values.put(5.5d);
+        values.put(11.0d);
+        JSONObject object = values.toJSONObject(keys);
+        assertEquals(1, object.length());
+        assertEquals(5.5d, object.get("a"));
+    }
+
+    public void testToJSONObjectNullKey() throws JSONException {
+        JSONArray keys = new JSONArray();
+        keys.put(JSONObject.NULL);
+        JSONArray values = new JSONArray();
+        values.put(5.5d);
+        JSONObject object = values.toJSONObject(keys);
+        assertEquals(1, object.length());
+        assertEquals(5.5d, object.get("null"));
+    }
+
     public void testPutUnsupportedNumbers() throws JSONException {
         JSONArray array = new JSONArray();
 
@@ -312,6 +371,18 @@
         }
     }
 
+    public void testPutUnsupportedNumbersAsObject() throws JSONException {
+        JSONArray array = new JSONArray();
+        array.put(Double.valueOf(Double.NaN));
+        array.put(Double.valueOf(Double.NEGATIVE_INFINITY));
+        array.put(Double.valueOf(Double.POSITIVE_INFINITY));
+        assertEquals(null, array.toString());
+    }
+
+    /**
+     * Although JSONArray is usually defensive about which numbers it accepts,
+     * it doesn't check inputs in its constructor.
+     */
     public void testCreateWithUnsupportedNumbers() throws JSONException {
         JSONArray array = new JSONArray(Arrays.asList(5.5, Double.NaN));
         assertEquals(2, array.length());
@@ -320,10 +391,81 @@
     }
 
     public void testToStringWithUnsupportedNumbers() throws JSONException {
-        // bogus behaviour: when the array contains an unsupported number, toString returns null
+        // when the array contains an unsupported number, toString returns null!
         JSONArray array = new JSONArray(Arrays.asList(5.5, Double.NaN));
         assertNull(array.toString());
     }
+    
+    public void testListConstructorCopiesContents() throws JSONException {
+        List<Object> contents = Arrays.<Object>asList(5);
+        JSONArray array = new JSONArray(contents);
+        contents.set(0, 10);
+        assertEquals(5, array.get(0));
+    }
+
+    public void testTokenerConstructor() throws JSONException {
+        JSONArray object = new JSONArray(new JSONTokener("[false]"));
+        assertEquals(1, object.length());
+        assertEquals(false, object.get(0));
+    }
+
+    public void testTokenerConstructorWrongType() throws JSONException {
+        try {
+            new JSONArray(new JSONTokener("{\"foo\": false}"));
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testTokenerConstructorNull() throws JSONException {
+        try {
+            new JSONArray((JSONTokener) null);
+            fail();
+        } catch (NullPointerException e) {
+        }
+    }
+
+    public void testTokenerConstructorParseFail() {
+        try {
+            new JSONArray(new JSONTokener("["));
+            fail();
+        } catch (JSONException e) {
+        } catch (StackOverflowError e) {
+            fail("Stack overflowed on input: \"[\"");
+        }
+    }
+
+    public void testStringConstructor() throws JSONException {
+        JSONArray object = new JSONArray("[false]");
+        assertEquals(1, object.length());
+        assertEquals(false, object.get(0));
+    }
+
+    public void testStringConstructorWrongType() throws JSONException {
+        try {
+            new JSONArray("{\"foo\": false}");
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testStringConstructorNull() throws JSONException {
+        try {
+            new JSONArray((String) null);
+            fail();
+        } catch (NullPointerException e) {
+        }
+    }
+
+    public void testStringConstructorParseFail() {
+        try {
+            new JSONArray("[");
+            fail();
+        } catch (JSONException e) {
+        } catch (StackOverflowError e) {
+            fail("Stack overflowed on input: \"[\"");
+        }
+    }
 
     public void testCreate() throws JSONException {
         JSONArray array = new JSONArray(Arrays.asList(5.5, true));
@@ -333,7 +475,32 @@
         assertEquals("[5.5,true]", array.toString());
     }
 
-    public void testParsingConstructor() {
-        fail("TODO");
+    public void testAccessOutOfBounds() throws JSONException {
+        JSONArray array = new JSONArray();
+        array.put("foo");
+        assertEquals(null, array.opt(3));
+        assertEquals(null, array.opt(-3));
+        assertEquals("", array.optString(3));
+        assertEquals("", array.optString(-3));
+        try {
+            array.get(3);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            array.get(-3);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            array.getString(3);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            array.getString(-3);
+            fail();
+        } catch (JSONException e) {
+        }
     }
 }
diff --git a/libcore/json/src/test/java/org/json/JSONObjectTest.java b/libcore/json/src/test/java/org/json/JSONObjectTest.java
new file mode 100644
index 0000000..e431096
--- /dev/null
+++ b/libcore/json/src/test/java/org/json/JSONObjectTest.java
@@ -0,0 +1,898 @@
+/*
+ * 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 org.json;
+
+import junit.framework.TestCase;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.*;
+
+/**
+ * This black box test was written without inspecting the non-free org.json sourcecode.
+ */
+public class JSONObjectTest extends TestCase {
+
+    public void testEmptyObject() throws JSONException {
+        JSONObject object = new JSONObject();
+        assertEquals(0, object.length());
+
+        // bogus (but documented) behaviour: returns null rather than the empty object!
+        assertNull(object.names());
+
+        // returns null rather than an empty array!
+        assertNull(object.toJSONArray(new JSONArray()));
+        assertEquals("{}", object.toString());
+        assertEquals("{}", object.toString(5));
+        try {
+            object.get("foo");
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.getBoolean("foo");
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.getDouble("foo");
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.getInt("foo");
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.getJSONArray("foo");
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.getJSONObject("foo");
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.getLong("foo");
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.getString("foo");
+            fail();
+        } catch (JSONException e) {
+        }
+        assertFalse(object.has("foo"));
+        assertTrue(object.isNull("foo")); // isNull also means "is not present"
+        assertNull(object.opt("foo"));
+        assertEquals(false, object.optBoolean("foo"));
+        assertEquals(true, object.optBoolean("foo", true));
+        assertEquals(Double.NaN, object.optDouble("foo"));
+        assertEquals(5.0, object.optDouble("foo", 5.0));
+        assertEquals(0, object.optInt("foo"));
+        assertEquals(5, object.optInt("foo", 5));
+        assertEquals(null, object.optJSONArray("foo"));
+        assertEquals(null, object.optJSONObject("foo"));
+        assertEquals(0, object.optLong("foo"));
+        assertEquals(Long.MAX_VALUE-1, object.optLong("foo", Long.MAX_VALUE-1));
+        assertEquals("", object.optString("foo")); // empty string is default!
+        assertEquals("bar", object.optString("foo", "bar"));
+        assertNull(object.remove("foo"));
+    }
+    
+    public void testEqualsAndHashCode() throws JSONException {
+        JSONObject a = new JSONObject();
+        JSONObject b = new JSONObject();
+
+        // JSON object doesn't override either equals or hashCode (!)
+        assertFalse(a.equals(b));
+        assertEquals(a.hashCode(), System.identityHashCode(a));
+    }
+
+    public void testGet() throws JSONException {
+        JSONObject object = new JSONObject();
+        Object value = new Object();
+        object.put("foo", value);
+        object.put("bar", new Object());
+        object.put("baz", new Object());
+        assertSame(value, object.get("foo"));
+        try {
+            object.get("FOO");
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.put(null, value);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.get(null);
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testPut() throws JSONException {
+        JSONObject object = new JSONObject();
+        assertSame(object, object.put("foo", true));
+        object.put("foo", false);
+        assertEquals(false, object.get("foo"));
+
+        object.put("foo", 5.0d);
+        assertEquals(5.0d, object.get("foo"));
+        object.put("foo", 0);
+        assertEquals(0, object.get("foo"));
+        object.put("bar", Long.MAX_VALUE - 1);
+        assertEquals(Long.MAX_VALUE - 1, object.get("bar"));
+        object.put("baz", "x");
+        assertEquals("x", object.get("baz"));
+        object.put("bar", JSONObject.NULL);
+        assertSame(JSONObject.NULL, object.get("bar"));
+    }
+
+    public void testPutNullRemoves() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", "bar");
+        object.put("foo", null);
+        assertEquals(0, object.length());
+        assertFalse(object.has("foo"));
+        try {
+            object.get("foo");
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testPutOpt() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", "bar");
+        object.putOpt("foo", null);
+        assertEquals("bar", object.get("foo"));
+        object.putOpt(null, null);
+        assertEquals(1, object.length());
+        object.putOpt(null, "bar");
+        assertEquals(1, object.length());
+    }
+
+    public void testPutOptUnsupportedNumbers() throws JSONException {
+        JSONObject object = new JSONObject();
+        try {
+            object.putOpt("foo", Double.NaN);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.putOpt("foo", Double.NEGATIVE_INFINITY);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.putOpt("foo", Double.POSITIVE_INFINITY);
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testRemove() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", "bar");
+        assertEquals(null, object.remove(null));
+        assertEquals(null, object.remove(""));
+        assertEquals(null, object.remove("bar"));
+        assertEquals("bar", object.remove("foo"));
+        assertEquals(null, object.remove("foo"));
+    }
+
+    public void testBooleans() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", true);
+        object.put("bar", false);
+        object.put("baz", "true");
+        object.put("quux", "false");
+        assertEquals(4, object.length());
+        assertEquals(true, object.getBoolean("foo"));
+        assertEquals(false, object.getBoolean("bar"));
+        assertEquals(true, object.getBoolean("baz"));
+        assertEquals(false, object.getBoolean("quux"));
+        assertFalse(object.isNull("foo"));
+        assertFalse(object.isNull("quux"));
+        assertTrue(object.has("foo"));
+        assertTrue(object.has("quux"));
+        assertFalse(object.has("missing"));
+        assertEquals(true, object.optBoolean("foo"));
+        assertEquals(false, object.optBoolean("bar"));
+        assertEquals(true, object.optBoolean("baz"));
+        assertEquals(false, object.optBoolean("quux"));
+        assertEquals(false, object.optBoolean("missing"));
+        assertEquals(true, object.optBoolean("foo", true));
+        assertEquals(false, object.optBoolean("bar", true));
+        assertEquals(true, object.optBoolean("baz", true));
+        assertEquals(false, object.optBoolean("quux", true));
+        assertEquals(true, object.optBoolean("missing", true));
+
+        object.put("foo", "truE");
+        object.put("bar", "FALSE");
+        assertEquals(true, object.getBoolean("foo"));
+        assertEquals(false, object.getBoolean("bar"));
+        assertEquals(true, object.optBoolean("foo"));
+        assertEquals(false, object.optBoolean("bar"));
+        assertEquals(true, object.optBoolean("foo", false));
+        assertEquals(false, object.optBoolean("bar", false));
+    }
+
+    public void testNumbers() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", Double.MIN_VALUE);
+        object.put("bar", 9223372036854775806L);
+        object.put("baz", Double.MAX_VALUE);
+        object.put("quux", -0d);
+        assertEquals(4, object.length());
+
+        String toString = object.toString();
+        assertTrue(toString, toString.contains("\"foo\":4.9E-324"));
+        assertTrue(toString, toString.contains("\"bar\":9223372036854775806"));
+        assertTrue(toString, toString.contains("\"baz\":1.7976931348623157E308"));
+
+        // toString() and getString() return different values for -0d!
+        assertTrue(toString, toString.contains("\"quux\":-0}") // no trailing decimal point
+                || toString.contains("\"quux\":-0,"));
+
+        assertEquals(Double.MIN_VALUE, object.get("foo"));
+        assertEquals(9223372036854775806L, object.get("bar"));
+        assertEquals(Double.MAX_VALUE, object.get("baz"));
+        assertEquals(-0d, object.get("quux"));
+        assertEquals(Double.MIN_VALUE, object.getDouble("foo"));
+        assertEquals(9.223372036854776E18, object.getDouble("bar"));
+        assertEquals(Double.MAX_VALUE, object.getDouble("baz"));
+        assertEquals(-0d, object.getDouble("quux"));
+        assertEquals(0, object.getLong("foo"));
+        assertEquals(9223372036854775806L, object.getLong("bar"));
+        assertEquals(Long.MAX_VALUE, object.getLong("baz"));
+        assertEquals(0, object.getLong("quux"));
+        assertEquals(0, object.getInt("foo"));
+        assertEquals(-2, object.getInt("bar"));
+        assertEquals(Integer.MAX_VALUE, object.getInt("baz"));
+        assertEquals(0, object.getInt("quux"));
+        assertEquals(Double.MIN_VALUE, object.opt("foo"));
+        assertEquals(9223372036854775806L, object.optLong("bar"));
+        assertEquals(Double.MAX_VALUE, object.optDouble("baz"));
+        assertEquals(0, object.optInt("quux"));
+        assertEquals(Double.MIN_VALUE, object.opt("foo"));
+        assertEquals(9223372036854775806L, object.optLong("bar"));
+        assertEquals(Double.MAX_VALUE, object.optDouble("baz"));
+        assertEquals(0, object.optInt("quux"));
+        assertEquals(Double.MIN_VALUE, object.optDouble("foo", 5.0d));
+        assertEquals(9223372036854775806L, object.optLong("bar", 1L));
+        assertEquals(Long.MAX_VALUE, object.optLong("baz", 1L));
+        assertEquals(0, object.optInt("quux", -1));
+        assertEquals("4.9E-324", object.getString("foo"));
+        assertEquals("9223372036854775806", object.getString("bar"));
+        assertEquals("1.7976931348623157E308", object.getString("baz"));
+        assertEquals("-0.0", object.getString("quux"));
+    }
+
+    public void testFloats() throws JSONException {
+        JSONObject object = new JSONObject();
+        try {
+            object.put("foo", (Float) Float.NaN);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.put("foo", (Float) Float.NEGATIVE_INFINITY);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.put("foo", (Float) Float.POSITIVE_INFINITY);
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testOtherNumbers() throws JSONException {
+        Number nan = new Number() {
+            public int intValue() {
+                throw new UnsupportedOperationException();
+            }
+            public long longValue() {
+                throw new UnsupportedOperationException();
+            }
+            public float floatValue() {
+                throw new UnsupportedOperationException();
+            }
+            public double doubleValue() {
+                return Double.NaN;
+            }
+            @Override public String toString() {
+                return "x";
+            }
+        };
+
+        JSONObject object = new JSONObject();
+        try {
+            object.put("foo", nan);
+            fail("Object.put() accepted a NaN (via a custom Number class)");
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testForeignObjects() throws JSONException {
+        Object foreign = new Object() {
+            @Override public String toString() {
+                return "x";
+            }
+        };
+
+        // foreign object types are accepted and treated as Strings!
+        JSONObject object = new JSONObject();
+        object.put("foo", foreign);
+        assertEquals("{\"foo\":\"x\"}", object.toString());
+    }
+
+    public void testNullKeys() {
+        try {
+            new JSONObject().put(null, false);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            new JSONObject().put(null, 0.0d);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            new JSONObject().put(null, 5);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            new JSONObject().put(null, 5L);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            new JSONObject().put(null, "foo");
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testStrings() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", "true");
+        object.put("bar", "5.5");
+        object.put("baz", "9223372036854775806");
+        object.put("quux", "null");
+        object.put("height", "5\"8' tall");
+
+        assertTrue(object.toString().contains("\"foo\":\"true\""));
+        assertTrue(object.toString().contains("\"bar\":\"5.5\""));
+        assertTrue(object.toString().contains("\"baz\":\"9223372036854775806\""));
+        assertTrue(object.toString().contains("\"quux\":\"null\""));
+        assertTrue(object.toString().contains("\"height\":\"5\\\"8' tall\""));
+
+        assertEquals("true", object.get("foo"));
+        assertEquals("null", object.getString("quux"));
+        assertEquals("5\"8' tall", object.getString("height"));
+        assertEquals("true", object.opt("foo"));
+        assertEquals("5.5", object.optString("bar"));
+        assertEquals("true", object.optString("foo", "x"));
+        assertFalse(object.isNull("foo"));
+
+        assertEquals(true, object.getBoolean("foo"));
+        assertEquals(true, object.optBoolean("foo"));
+        assertEquals(true, object.optBoolean("foo", false));
+        assertEquals(0, object.optInt("foo"));
+        assertEquals(-2, object.optInt("foo", -2));
+
+        assertEquals(5.5d, object.getDouble("bar"));
+        assertEquals(5L, object.getLong("bar"));
+        assertEquals(5, object.getInt("bar"));
+        assertEquals(5, object.optInt("bar", 3));
+
+        // The last digit of the string is a 6 but getLong returns a 7. It's probably parsing as a
+        // double and then converting that to a long. This is consistent with JavaScript.
+        assertEquals(9223372036854775807L, object.getLong("baz"));
+        assertEquals(9.223372036854776E18, object.getDouble("baz"));
+        assertEquals(Integer.MAX_VALUE, object.getInt("baz"));
+
+        assertFalse(object.isNull("quux"));
+        try {
+            object.getDouble("quux");
+            fail();
+        } catch (JSONException e) {
+        }
+        assertEquals(Double.NaN, object.optDouble("quux"));
+        assertEquals(-1.0d, object.optDouble("quux", -1.0d));
+
+        object.put("foo", "TRUE");
+        assertEquals(true, object.getBoolean("foo"));
+    }
+
+    public void testJSONObjects() throws JSONException {
+        JSONObject object = new JSONObject();
+
+        JSONArray a = new JSONArray();
+        JSONObject b = new JSONObject();
+        object.put("foo", a);
+        object.put("bar", b);
+
+        assertSame(a, object.getJSONArray("foo"));
+        assertSame(b, object.getJSONObject("bar"));
+        try {
+            object.getJSONObject("foo");
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.getJSONArray("bar");
+            fail();
+        } catch (JSONException e) {
+        }
+        assertEquals(a, object.optJSONArray("foo"));
+        assertEquals(b, object.optJSONObject("bar"));
+        assertEquals(null, object.optJSONArray("bar"));
+        assertEquals(null, object.optJSONObject("foo"));
+    }
+
+    public void testToJSONArray() throws JSONException {
+        JSONObject object = new JSONObject();
+        Object value = new Object();
+        object.put("foo", true);
+        object.put("bar", 5.0d);
+        object.put("baz", -0.0d);
+        object.put("quux", value);
+
+        JSONArray names = new JSONArray();
+        names.put("baz");
+        names.put("quux");
+        names.put("foo");
+
+        JSONArray array = object.toJSONArray(names);
+        assertEquals(-0.0d, array.get(0));
+        assertEquals(value, array.get(1));
+        assertEquals(true, array.get(2));
+
+        object.put("foo", false);
+        assertEquals(true, array.get(2));
+    }
+
+    public void testToJSONArrayMissingNames() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", true);
+        object.put("bar", 5.0d);
+        object.put("baz", JSONObject.NULL);
+
+        JSONArray names = new JSONArray();
+        names.put("bar");
+        names.put("foo");
+        names.put("quux");
+        names.put("baz");
+
+        JSONArray array = object.toJSONArray(names);
+        assertEquals(4, array.length());
+
+        assertEquals(5.0d, array.get(0));
+        assertEquals(true, array.get(1));
+        try {
+            array.get(2);
+            fail();
+        } catch (JSONException e) {
+        }
+        assertEquals(JSONObject.NULL, array.get(3));
+    }
+
+    public void testToJSONArrayNull() throws JSONException {
+        JSONObject object = new JSONObject();
+        assertEquals(null, object.toJSONArray(null));
+        object.put("foo", 5);
+        try {
+            object.toJSONArray(null);
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testToJSONArrayEndsUpEmpty() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", 5);
+        JSONArray array = new JSONArray();
+        array.put("bar");
+        assertEquals(1, object.toJSONArray(array).length());
+    }
+
+    public void testToJSONArrayNonString() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", 5);
+        object.put("null", 10);
+        object.put("false", 15);
+
+        JSONArray names = new JSONArray();
+        names.put(JSONObject.NULL);
+        names.put(false);
+        names.put("foo");
+
+        // array elements are converted to strings to do name lookups on the map!
+        JSONArray array = object.toJSONArray(names);
+        assertEquals(3, array.length());
+        assertEquals(10, array.get(0));
+        assertEquals(15, array.get(1));
+        assertEquals(5, array.get(2));
+    }
+
+    public void testPutUnsupportedNumbers() throws JSONException {
+        JSONObject object = new JSONObject();
+        try {
+            object.put("foo", Double.NaN);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.put("foo", Double.NEGATIVE_INFINITY);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.put("foo", Double.POSITIVE_INFINITY);
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testPutUnsupportedNumbersAsObjects() throws JSONException {
+        JSONObject object = new JSONObject();
+        try {
+            object.put("foo", (Double) Double.NaN);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.put("foo", (Double) Double.NEGATIVE_INFINITY);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            object.put("foo", (Double) Double.POSITIVE_INFINITY);
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    /**
+     * Although JSONObject is usually defensive about which numbers it accepts,
+     * it doesn't check inputs in its constructor.
+     */
+    public void testCreateWithUnsupportedNumbers() throws JSONException {
+        Map<String, Object> contents = new HashMap<String, Object>();
+        contents.put("foo", Double.NaN);
+        contents.put("bar", Double.NEGATIVE_INFINITY);
+        contents.put("baz", Double.POSITIVE_INFINITY);
+
+        JSONObject object = new JSONObject(contents);
+        assertEquals(Double.NaN, object.get("foo"));
+        assertEquals(Double.NEGATIVE_INFINITY, object.get("bar"));
+        assertEquals(Double.POSITIVE_INFINITY, object.get("baz"));
+    }
+
+    public void testToStringWithUnsupportedNumbers() {
+        // when the object contains an unsupported number, toString returns null!
+        JSONObject object = new JSONObject(Collections.singletonMap("foo", Double.NaN));
+        assertEquals(null, object.toString());
+    }
+
+    public void testMapConstructorCopiesContents() throws JSONException {
+        Map<String, Object> contents = new HashMap<String, Object>();
+        contents.put("foo", 5);
+        JSONObject object = new JSONObject(contents);
+        contents.put("foo", 10);
+        assertEquals(5, object.get("foo"));
+    }
+
+    public void testMapConstructorWithBogusEntries() {
+        Map<Object, Object> contents = new HashMap<Object, Object>();
+        contents.put(5, 5);
+
+        try {
+            new JSONObject(contents);
+            fail("JSONObject constructor doesn't validate its input!");
+        } catch (Exception e) {
+        }
+    }
+
+    public void testTokenerConstructor() throws JSONException {
+        JSONObject object = new JSONObject(new JSONTokener("{\"foo\": false}"));
+        assertEquals(1, object.length());
+        assertEquals(false, object.get("foo"));
+    }
+
+    public void testTokenerConstructorWrongType() throws JSONException {
+        try {
+            new JSONObject(new JSONTokener("[\"foo\", false]"));
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testTokenerConstructorNull() throws JSONException {
+        try {
+            new JSONObject((JSONTokener) null);
+            fail();
+        } catch (NullPointerException e) {
+        }
+    }
+
+    public void testTokenerConstructorParseFail() {
+        try {
+            new JSONObject(new JSONTokener("{"));
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testStringConstructor() throws JSONException {
+        JSONObject object = new JSONObject("{\"foo\": false}");
+        assertEquals(1, object.length());
+        assertEquals(false, object.get("foo"));
+    }
+
+    public void testStringConstructorWrongType() throws JSONException {
+        try {
+            new JSONObject("[\"foo\", false]");
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testStringConstructorNull() throws JSONException {
+        try {
+            new JSONObject((String) null);
+            fail();
+        } catch (NullPointerException e) {
+        }
+    }
+
+    public void testStringonstructorParseFail() {
+        try {
+            new JSONObject("{");
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testCopyConstructor() throws JSONException {
+        JSONObject source = new JSONObject();
+        source.put("a", JSONObject.NULL);
+        source.put("b", false);
+        source.put("c", 5);
+
+        JSONObject copy = new JSONObject(source, new String[] { "a", "c" });
+        assertEquals(2, copy.length());
+        assertEquals(JSONObject.NULL, copy.get("a"));
+        assertEquals(5, copy.get("c"));
+        assertEquals(null, copy.opt("b"));
+    }
+
+    public void testCopyConstructorMissingName() throws JSONException {
+        JSONObject source = new JSONObject();
+        source.put("a", JSONObject.NULL);
+        source.put("b", false);
+        source.put("c", 5);
+
+        JSONObject copy = new JSONObject(source, new String[]{ "a", "c", "d" });
+        assertEquals(2, copy.length());
+        assertEquals(JSONObject.NULL, copy.get("a"));
+        assertEquals(5, copy.get("c"));
+        assertEquals(0, copy.optInt("b"));
+    }
+
+    public void testAccumulateMutatesInPlace() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", 5);
+        object.accumulate("foo", 6);
+        JSONArray array = object.getJSONArray("foo");
+        assertEquals("[5,6]", array.toString());
+        object.accumulate("foo", 7);
+        assertEquals("[5,6,7]", array.toString());
+    }
+
+    public void testAccumulateExistingArray() throws JSONException {
+        JSONArray array = new JSONArray();
+        JSONObject object = new JSONObject();
+        object.put("foo", array);
+        object.accumulate("foo", 5);
+        assertEquals("[5]", array.toString());
+    }
+
+    public void testAccumulatePutArray() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.accumulate("foo", 5);
+        assertEquals("{\"foo\":5}", object.toString());
+        object.accumulate("foo", new JSONArray());
+        assertEquals("{\"foo\":[5,[]]}", object.toString());
+    }
+
+    public void testAccumulateNull() {
+        JSONObject object = new JSONObject();
+        try {
+            object.accumulate(null, 5);
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testEmptyStringKey() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("", 5);
+        assertEquals(5, object.get(""));
+        assertEquals("{\"\":5}", object.toString());
+    }
+
+    public void testNullValue() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", JSONObject.NULL);
+        object.put("bar", null);
+
+        // there are two ways to represent null; each behaves differently!
+        assertTrue(object.has("foo"));
+        assertFalse(object.has("bar"));
+        assertTrue(object.isNull("foo"));
+        assertTrue(object.isNull("bar"));
+    }
+
+    public void testHas() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", 5);
+        assertTrue(object.has("foo"));
+        assertFalse(object.has("bar"));
+        assertFalse(object.has(null));
+    }
+    
+    public void testOptNull() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", "bar");
+        assertEquals(null, object.opt(null));
+        assertEquals(false, object.optBoolean(null));
+        assertEquals(Double.NaN, object.optDouble(null));
+        assertEquals(0, object.optInt(null));
+        assertEquals(0L, object.optLong(null));
+        assertEquals(null, object.optJSONArray(null));
+        assertEquals(null, object.optJSONObject(null));
+        assertEquals("", object.optString(null));
+        assertEquals(true, object.optBoolean(null, true));
+        assertEquals(0.0d, object.optDouble(null, 0.0d));
+        assertEquals(1, object.optInt(null, 1));
+        assertEquals(1L, object.optLong(null, 1L));
+        assertEquals("baz", object.optString(null, "baz"));
+    }
+
+    public void testToStringWithIndentFactor() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", new JSONArray(Arrays.asList(5, 6)));
+        object.put("bar", new JSONObject());
+        String foobar = "{\n" +
+                "     \"foo\": [\n" +
+                "          5,\n" +
+                "          6\n" +
+                "     ],\n" +
+                "     \"bar\": {}\n" +
+                "}";
+        String barfoo = "{\n" +
+                "     \"bar\": {},\n" +
+                "     \"foo\": [\n" +
+                "          5,\n" +
+                "          6\n" +
+                "     ]\n" +
+                "}";
+        String string = object.toString(5);
+        assertTrue(string, foobar.equals(string) || barfoo.equals(string));
+    }
+
+    public void testNames() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", 5);
+        object.put("bar", 6);
+        object.put("baz", 7);
+        JSONArray array = object.names();
+        assertTrue(array.toString().contains("foo"));
+        assertTrue(array.toString().contains("bar"));
+        assertTrue(array.toString().contains("baz"));
+    }
+
+    public void testKeysEmptyObject() {
+        JSONObject object = new JSONObject();
+        assertFalse(object.keys().hasNext());
+        try {
+            object.keys().next();
+            fail();
+        } catch (NoSuchElementException e) {
+        }
+    }
+
+    public void testKeys() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", 5);
+        object.put("bar", 6);
+        object.put("foo", 7);
+
+        @SuppressWarnings("unchecked")
+        Iterator<String> keys = (Iterator<String>) object.keys();
+        Set<String> result = new HashSet<String>();
+        assertTrue(keys.hasNext());
+        result.add(keys.next());
+        assertTrue(keys.hasNext());
+        result.add(keys.next());
+        assertFalse(keys.hasNext());
+        assertEquals(new HashSet<String>(Arrays.asList("foo", "bar")), result);
+
+        try {
+            keys.next();
+            fail();
+        } catch (NoSuchElementException e) {
+        }
+    }
+
+    public void testMutatingKeysMutatesObject() throws JSONException {
+        JSONObject object = new JSONObject();
+        object.put("foo", 5);
+        Iterator keys = object.keys();
+        keys.next();
+        keys.remove();
+        assertEquals(0, object.length());
+    }
+
+    public void testQuote() {
+        // covered by JSONStringerTest.testEscaping
+    }
+
+    public void testQuoteNull() throws JSONException {
+        assertEquals("\"\"", JSONObject.quote(null));
+    }
+
+    public void testNumberToString() throws JSONException {
+        assertEquals("5", JSONObject.numberToString(5));
+        assertEquals("-0", JSONObject.numberToString(-0.0d));
+        assertEquals("9223372036854775806", JSONObject.numberToString(9223372036854775806L));
+        assertEquals("4.9E-324", JSONObject.numberToString(Double.MIN_VALUE));
+        assertEquals("1.7976931348623157E308", JSONObject.numberToString(Double.MAX_VALUE));
+        try {
+            JSONObject.numberToString(Double.NaN);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            JSONObject.numberToString(Double.NEGATIVE_INFINITY);
+            fail();
+        } catch (JSONException e) {
+        }
+        try {
+            JSONObject.numberToString(Double.POSITIVE_INFINITY);
+            fail();
+        } catch (JSONException e) {
+        }
+        assertEquals("0.001", JSONObject.numberToString(new BigDecimal("0.001")));
+        assertEquals("9223372036854775806",
+                JSONObject.numberToString(new BigInteger("9223372036854775806")));
+        try {
+            JSONObject.numberToString(null);
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+}
diff --git a/libcore/json/src/test/java/org/json/JSONStringerTest.java b/libcore/json/src/test/java/org/json/JSONStringerTest.java
index a30df9e..64c3a74 100644
--- a/libcore/json/src/test/java/org/json/JSONStringerTest.java
+++ b/libcore/json/src/test/java/org/json/JSONStringerTest.java
@@ -1,11 +1,11 @@
-/**
+/*
  * 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
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -24,7 +24,7 @@
 public class JSONStringerTest extends TestCase {
 
     public void testEmptyStringer() {
-        // bogus behaviour: why isn't this the empty string?
+        // why isn't this the empty string?
         assertNull(new JSONStringer().toString());
     }
 
@@ -62,6 +62,16 @@
         assertEquals("[false,5,5,\"five\",null]", stringer.toString());
     }
 
+    public void testValueObjectMethods() throws JSONException {
+        JSONStringer stringer = new JSONStringer();
+        stringer.array();
+        stringer.value(Boolean.FALSE);
+        stringer.value(Double.valueOf(5.0));
+        stringer.value(Long.valueOf(5L));
+        stringer.endArray();
+        assertEquals("[false,5,5]", stringer.toString());
+    }
+
     public void testKeyValue() throws JSONException {
         JSONStringer stringer = new JSONStringer();
         stringer.object();
@@ -187,32 +197,34 @@
 
     public void testEscaping() throws JSONException {
         assertEscapedAllWays("a", "a");
-        assertEscapedAllWays("a\"", "a\\\"");
-        assertEscapedAllWays("\"", "\\\"");
+        assertEscapedAllWays("a\\\"", "a\"");
+        assertEscapedAllWays("\\\"", "\"");
         assertEscapedAllWays(":", ":");
         assertEscapedAllWays(",", ",");
-        assertEscapedAllWays("\n", "\\n");
-        assertEscapedAllWays("\t", "\\t");
+        assertEscapedAllWays("\\b", "\b");
+        assertEscapedAllWays("\\f", "\f");
+        assertEscapedAllWays("\\n", "\n");
+        assertEscapedAllWays("\\r", "\r");
+        assertEscapedAllWays("\\t", "\t");
         assertEscapedAllWays(" ", " ");
-        assertEscapedAllWays("\\", "\\\\");
+        assertEscapedAllWays("\\\\", "\\");
         assertEscapedAllWays("{", "{");
         assertEscapedAllWays("}", "}");
         assertEscapedAllWays("[", "[");
         assertEscapedAllWays("]", "]");
-
-        // how does it decide which characters to escape?
-        assertEscapedAllWays("\0", "\\u0000");
-        assertEscapedAllWays("\u0019", "\\u0019");
-        assertEscapedAllWays("\u0020", " ");
+        assertEscapedAllWays("\\u0000", "\0");
+        assertEscapedAllWays("\\u0019", "\u0019");
+        assertEscapedAllWays(" ", "\u0020");
     }
 
-    private void assertEscapedAllWays(String original, String escaped) throws JSONException {
+    private void assertEscapedAllWays(String escaped, String original) throws JSONException {
         assertEquals("{\"" + escaped + "\":false}",
                 new JSONStringer().object().key(original).value(false).endObject().toString());
         assertEquals("{\"a\":\"" + escaped + "\"}",
                 new JSONStringer().object().key("a").value(original).endObject().toString());
         assertEquals("[\"" + escaped + "\"]",
                 new JSONStringer().array().value(original).endArray().toString());
+        assertEquals("\"" + escaped + "\"", JSONObject.quote(original));
     }
 
     public void testJSONArrayAsValue() throws JSONException {
@@ -235,7 +247,7 @@
         assertEquals("{\"b\":{\"a\":false}}", stringer.toString());
     }
 
-    public void testArrayNestingMaxDepthIs20() throws JSONException {
+    public void testArrayNestingMaxDepthSupports20() throws JSONException {
         JSONStringer stringer = new JSONStringer();
         for (int i = 0; i < 20; i++) {
             stringer.array();
@@ -249,14 +261,9 @@
         for (int i = 0; i < 20; i++) {
             stringer.array();
         }
-        try {
-            stringer.array();
-            fail();
-        } catch (JSONException e) {
-        }
     }
 
-    public void testObjectNestingMaxDepthIs20() throws JSONException {
+    public void testObjectNestingMaxDepthSupports20() throws JSONException {
         JSONStringer stringer = new JSONStringer();
         for (int i = 0; i < 20; i++) {
             stringer.object();
@@ -275,14 +282,9 @@
             stringer.object();
             stringer.key("a");
         }
-        try {
-            stringer.object();
-            fail();
-        } catch (JSONException e) {
-        }
     }
 
-    public void testMixedMaxDepth() throws JSONException {
+    public void testMixedMaxDepthSupports20() throws JSONException {
         JSONStringer stringer = new JSONStringer();
         for (int i = 0; i < 20; i+=2) {
             stringer.array();
@@ -304,11 +306,6 @@
             stringer.object();
             stringer.key("a");
         }
-        try {
-            stringer.array();
-            fail();
-        } catch (JSONException e) {
-        }
     }
 
     public void testMaxDepthWithArrayValue() throws JSONException {
diff --git a/libcore/json/src/test/java/org/json/JSONTokenerTest.java b/libcore/json/src/test/java/org/json/JSONTokenerTest.java
index 1409a3b..70b7384 100644
--- a/libcore/json/src/test/java/org/json/JSONTokenerTest.java
+++ b/libcore/json/src/test/java/org/json/JSONTokenerTest.java
@@ -1,11 +1,11 @@
-/**
+/*
  * 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
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,6 +17,7 @@
 package org.json;
 
 import junit.framework.TestCase;
+import junit.framework.AssertionFailedError;
 
 /**
  * This black box test was written without inspecting the non-free org.json sourcecode.
@@ -24,7 +25,7 @@
 public class JSONTokenerTest extends TestCase {
 
     public void testNulls() throws JSONException {
-        // bogus behaviour: JSONTokener accepts null, only to fail later on almost all APIs.
+        // JSONTokener accepts null, only to fail later on almost all APIs!
         new JSONTokener(null).back();
 
         try {
@@ -147,12 +148,6 @@
         }
         assertEquals('E', abcdeTokener.nextClean());
         assertEquals('\0', abcdeTokener.next());
-        try {
-            // bogus behaviour: returning an empty string should be valid
-            abcdeTokener.next(0);
-            fail();
-        } catch (JSONException e) {
-        }
         assertFalse(abcdeTokener.more());
         abcdeTokener.back();
         assertTrue(abcdeTokener.more());
@@ -174,7 +169,7 @@
         abcTokener.back();
         abcTokener.back();
         abcTokener.back();
-        abcTokener.back(); // bogus behaviour: you can back up before the beginning of a String
+        abcTokener.back(); // you can back up before the beginning of a String!
         assertEquals('A', abcTokener.next());
     }
 
@@ -209,26 +204,31 @@
             fail();
         } catch (JSONException e) {
         }
+    }
+
+    public void testNextNWithAllRemaining() throws JSONException {
+        JSONTokener tokener = new JSONTokener("ABCDEF");
+        tokener.next(3);
         try {
-            // bogus behaviour: there should be 3 characters left, but there must be an off-by-one
-            // error in the implementation.
-            assertEquals("DEF", abcdeTokener.next(3));
-            fail();
+            tokener.next(3);
         } catch (JSONException e) {
+            AssertionFailedError error = new AssertionFailedError("off-by-one error?");
+            error.initCause(e);
+            throw error;
         }
-        assertEquals("DE", abcdeTokener.next(2));
-        assertEquals('F', abcdeTokener.next());
+    }
+
+    public void testNext0() throws JSONException {
+        JSONTokener tokener = new JSONTokener("ABCDEF");
+        tokener.next(5);
+        tokener.next();
         try {
-            // bogus behaviour: returning an empty string should be valid
-            abcdeTokener.next(0);
-            fail();
+            tokener.next(0);
         } catch (JSONException e) {
+            Error error = new AssertionFailedError("Returning an empty string should be valid");
+            error.initCause(e);
+            throw error;
         }
-        abcdeTokener.back();
-        abcdeTokener.back();
-        abcdeTokener.back();
-        assertEquals("DE", abcdeTokener.next(2));
-        assertEquals('F', abcdeTokener.next());
     }
 
     public void testNextCleanComments() throws JSONException {
@@ -241,6 +241,24 @@
         assertEquals('\0', tokener.nextClean());
     }
 
+    public void testNextCleanNestedCStyleComments() throws JSONException {
+        JSONTokener tokener = new JSONTokener("A /* B /* C */ D */ E");
+        assertEquals('A', tokener.nextClean());
+        assertEquals('D', tokener.nextClean());
+        assertEquals('*', tokener.nextClean());
+        assertEquals('/', tokener.nextClean());
+        assertEquals('E', tokener.nextClean());
+    }
+
+    public void testNextCleanCommentsTrailingSingleSlash() throws JSONException {
+        JSONTokener tokener = new JSONTokener(" / S /");
+        assertEquals('/', tokener.nextClean());
+        assertEquals('S', tokener.nextClean());
+        assertEquals('/', tokener.nextClean());
+        assertEquals("nextClean doesn't consume a trailing slash",
+                '\0', tokener.nextClean());
+    }
+
     public void testNextCleanTrailingOpenComment() throws JSONException {
         try {
             new JSONTokener("  /* ").nextClean();
@@ -256,55 +274,54 @@
         assertEquals('B', new JSONTokener("  // \r  B ").nextClean());
     }
 
+    public void testNextCleanSkippedWhitespace() throws JSONException {
+        assertEquals("character tabulation", 'A', new JSONTokener("\tA").nextClean());
+        assertEquals("line feed",            'A', new JSONTokener("\nA").nextClean());
+        assertEquals("carriage return",      'A', new JSONTokener("\rA").nextClean());
+        assertEquals("space",                'A', new JSONTokener(" A").nextClean());
+    }
+
     /**
      * Tests which characters tokener treats as ignorable whitespace. See Kevin Bourrillion's
      * <a href="https://spreadsheets.google.com/pub?key=pd8dAQyHbdewRsnE5x5GzKQ">list
      * of whitespace characters</a>.
      */
-    public void testNextCleanWhitespace() throws JSONException {
-        // This behaviour contradicts the JSON spec. It claims the only space
-        // characters are space, tab, newline and carriage return. But it treats
-        // many characters like whitespace! These are the same whitespace
-        // characters used by String.trim(), with the exception of '\0'.
-        assertEquals("character tabulation",      'A', new JSONTokener("\u0009A").nextClean());
-        assertEquals("line feed",                 'A', new JSONTokener("\nA").nextClean());
-        assertEquals("line tabulation",           'A', new JSONTokener("\u000bA").nextClean());
-        assertEquals("form feed",                 'A', new JSONTokener("\u000cA").nextClean());
-        assertEquals("carriage return",           'A', new JSONTokener("\rA").nextClean());
-        assertEquals("information separator 4",   'A', new JSONTokener("\u001cA").nextClean());
-        assertEquals("information separator 3",   'A', new JSONTokener("\u001dA").nextClean());
-        assertEquals("information separator 2",   'A', new JSONTokener("\u001eA").nextClean());
-        assertEquals("information separator 1",   'A', new JSONTokener("\u001fA").nextClean());
-        assertEquals("space",                     'A', new JSONTokener("\u0020A").nextClean());
-        for (char c = '\u0002'; c < ' '; c++) {
-            assertEquals('A', new JSONTokener(new String(new char[] { ' ', c, 'A' })).nextClean());
-        }
+    public void testNextCleanRetainedWhitespace() throws JSONException {
+        assertNotClean("null",                      '\u0000');
+        assertNotClean("next line",                 '\u0085');
+        assertNotClean("non-breaking space",        '\u00a0');
+        assertNotClean("ogham space mark",          '\u1680');
+        assertNotClean("mongolian vowel separator", '\u180e');
+        assertNotClean("en quad",                   '\u2000');
+        assertNotClean("em quad",                   '\u2001');
+        assertNotClean("en space",                  '\u2002');
+        assertNotClean("em space",                  '\u2003');
+        assertNotClean("three-per-em space",        '\u2004');
+        assertNotClean("four-per-em space",         '\u2005');
+        assertNotClean("six-per-em space",          '\u2006');
+        assertNotClean("figure space",              '\u2007');
+        assertNotClean("punctuation space",         '\u2008');
+        assertNotClean("thin space",                '\u2009');
+        assertNotClean("hair space",                '\u200a');
+        assertNotClean("zero-width space",          '\u200b');
+        assertNotClean("left-to-right mark",        '\u200e');
+        assertNotClean("right-to-left mark",        '\u200f');
+        assertNotClean("line separator",            '\u2028');
+        assertNotClean("paragraph separator",       '\u2029');
+        assertNotClean("narrow non-breaking space", '\u202f');
+        assertNotClean("medium mathematical space", '\u205f');
+        assertNotClean("ideographic space",         '\u3000');
+        assertNotClean("line tabulation",           '\u000b');
+        assertNotClean("form feed",                 '\u000c');
+        assertNotClean("information separator 4",   '\u001c');
+        assertNotClean("information separator 3",   '\u001d');
+        assertNotClean("information separator 2",   '\u001e');
+        assertNotClean("information separator 1",   '\u001f');
+    }
 
-        // These characters are neither whitespace in the JSON spec nor the implementation
-        assertEquals("null",                      '\u0000', new JSONTokener("\u0000A").nextClean());
-        assertEquals("next line",                 '\u0085', new JSONTokener("\u0085A").nextClean());
-        assertEquals("non-breaking space",        '\u00a0', new JSONTokener("\u00a0A").nextClean());
-        assertEquals("ogham space mark",          '\u1680', new JSONTokener("\u1680A").nextClean());
-        assertEquals("mongolian vowel separator", '\u180e', new JSONTokener("\u180eA").nextClean());
-        assertEquals("en quad",                   '\u2000', new JSONTokener("\u2000A").nextClean());
-        assertEquals("em quad",                   '\u2001', new JSONTokener("\u2001A").nextClean());
-        assertEquals("en space",                  '\u2002', new JSONTokener("\u2002A").nextClean());
-        assertEquals("em space",                  '\u2003', new JSONTokener("\u2003A").nextClean());
-        assertEquals("three-per-em space",        '\u2004', new JSONTokener("\u2004A").nextClean());
-        assertEquals("four-per-em space",         '\u2005', new JSONTokener("\u2005A").nextClean());
-        assertEquals("six-per-em space",          '\u2006', new JSONTokener("\u2006A").nextClean());
-        assertEquals("figure space",              '\u2007', new JSONTokener("\u2007A").nextClean());
-        assertEquals("punctuation space",         '\u2008', new JSONTokener("\u2008A").nextClean());
-        assertEquals("thin space",                '\u2009', new JSONTokener("\u2009A").nextClean());
-        assertEquals("hair space",                '\u200a', new JSONTokener("\u200aA").nextClean());
-        assertEquals("zero-width space",          '\u200b', new JSONTokener("\u200bA").nextClean());
-        assertEquals("left-to-right mark",        '\u200e', new JSONTokener("\u200eA").nextClean());
-        assertEquals("right-to-left mark",        '\u200f', new JSONTokener("\u200fA").nextClean());
-        assertEquals("line separator",            '\u2028', new JSONTokener("\u2028A").nextClean());
-        assertEquals("paragraph separator",       '\u2029', new JSONTokener("\u2029A").nextClean());
-        assertEquals("narrow non-breaking space", '\u202f', new JSONTokener("\u202fA").nextClean());
-        assertEquals("medium mathematical space", '\u205f', new JSONTokener("\u205fA").nextClean());
-        assertEquals("ideographic space",         '\u3000', new JSONTokener("\u3000A").nextClean());
+    private void assertNotClean(String name, char c) throws JSONException {
+        assertEquals("The character " + name + " is not whitespace according to the JSON spec.",
+                c, new JSONTokener(new String(new char[] { c, 'A' })).nextClean());
     }
 
     public void testNextString() throws JSONException {
@@ -374,6 +391,7 @@
         try {
             new JSONTokener("abc\\u002\"").nextString('"');
             fail();
+        } catch (NumberFormatException e) {
         } catch (JSONException e) {
         }
         try {
@@ -433,15 +451,6 @@
         assertEquals("ABC", tokener.nextTo("\n"));
         assertEquals("", tokener.nextTo("\n"));
 
-        // Bogus behaviour: the tokener stops after \0 always
-        tokener = new JSONTokener(" \0\t \fABC \n DEF");
-        assertEquals("", tokener.nextTo("D"));
-        assertEquals('\t', tokener.next());
-        assertEquals("ABC", tokener.nextTo("D"));
-        tokener = new JSONTokener("ABC\0DEF");
-        assertEquals("ABC", tokener.nextTo("\0"));
-        assertEquals("DEF", tokener.nextTo("\0"));
-
         tokener = new JSONTokener("");
         try {
             tokener.nextTo(null);
@@ -450,6 +459,32 @@
         }
     }
 
+    public void testNextToTrimming() {
+        assertEquals("ABC", new JSONTokener("\t ABC \tDEF").nextTo("DE"));
+        assertEquals("ABC", new JSONTokener("\t ABC \tDEF").nextTo('D'));
+    }
+
+    public void testNextToTrailing() {
+        assertEquals("ABC DEF", new JSONTokener("\t ABC DEF \t").nextTo("G"));
+        assertEquals("ABC DEF", new JSONTokener("\t ABC DEF \t").nextTo('G'));
+    }
+
+    public void testNextToDoesntStopOnNull() {
+        String message = "nextTo() shouldn't stop after \\0 characters";
+        JSONTokener tokener = new JSONTokener(" \0\t \fABC \n DEF");
+        assertEquals(message, "ABC", tokener.nextTo("D"));
+        assertEquals(message, '\n', tokener.next());
+        assertEquals(message, "", tokener.nextTo("D"));
+    }
+
+    public void testNextToConsumesNull() {
+        String message = "nextTo shouldn't consume \\0.";
+        JSONTokener tokener = new JSONTokener("ABC\0DEF");
+        assertEquals(message, "ABC", tokener.nextTo("\0"));
+        assertEquals(message, '\0', tokener.next());
+        assertEquals(message, "DEF", tokener.nextTo("\0"));
+    }
+
     public void testSkipPast() {
         JSONTokener tokener = new JSONTokener("ABCDEF");
         tokener.skipPast("ABC");
@@ -509,11 +544,6 @@
         tokener.skipTo('A');
         assertEquals('F', tokener.next());
 
-        tokener = new JSONTokener("ABC\0DEF");
-        tokener.skipTo('F');
-        // bogus behaviour: skipTo gives up when it sees '\0'
-        assertEquals('A', tokener.next());
-
         tokener = new JSONTokener("ABC\nDEF");
         tokener.skipTo('F');
         assertEquals('F', tokener.next());
@@ -527,6 +557,12 @@
         assertEquals('D', tokener.next());
     }
 
+    public void testSkipToStopsOnNull() {
+        JSONTokener tokener = new JSONTokener("ABC\0DEF");
+        tokener.skipTo('F');
+        assertEquals("skipTo shouldn't stop when it sees '\\0'", 'F', tokener.next());
+    }
+
     public void testDehexchar() {
         assertEquals( 0, JSONTokener.dehexchar('0'));
         assertEquals( 1, JSONTokener.dehexchar('1'));
@@ -558,8 +594,4 @@
             assertEquals("dehexchar " + c, -1, JSONTokener.dehexchar((char) c));
         }
     }
-
-    public void testNextValue() {
-        fail("TODO");
-    }
 }
diff --git a/libcore/json/src/test/java/org/json/ParsingTest.java b/libcore/json/src/test/java/org/json/ParsingTest.java
new file mode 100644
index 0000000..16b9116
--- /dev/null
+++ b/libcore/json/src/test/java/org/json/ParsingTest.java
@@ -0,0 +1,260 @@
+/*
+ * 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 org.json;
+
+import junit.framework.TestCase;
+import junit.framework.AssertionFailedError;
+
+import java.util.*;
+
+public class ParsingTest extends TestCase {
+
+    public void testParsingNoObjects() {
+        try {
+            new JSONTokener("").nextValue();
+            fail();
+        } catch (JSONException e) {
+        }
+    }
+
+    public void testParsingLiterals() throws JSONException {
+        assertParsed(Boolean.TRUE, "true");
+        assertParsed(Boolean.FALSE, "false");
+        assertParsed(JSONObject.NULL, "null");
+        assertParsed(JSONObject.NULL, "NULL");
+        assertParsed(Boolean.FALSE, "False");
+        assertParsed(Boolean.TRUE, "truE");
+    }
+
+    public void testParsingQuotedStrings() throws JSONException {
+        assertParsed("abc", "\"abc\"");
+        assertParsed("123", "\"123\"");
+        assertParsed("foo\nbar", "\"foo\\nbar\"");
+        assertParsed("foo bar", "\"foo\\u0020bar\"");
+        assertParsed("\"{}[]/\\:,=;#", "\"\\\"{}[]/\\\\:,=;#\"");
+    }
+
+    public void testParsingSingleQuotedStrings() throws JSONException {
+        assertParsed("abc", "'abc'");
+        assertParsed("123", "'123'");
+        assertParsed("foo\nbar", "'foo\\nbar'");
+        assertParsed("foo bar", "'foo\\u0020bar'");
+        assertParsed("\"{}[]/\\:,=;#", "'\\\"{}[]/\\\\:,=;#'");
+    }
+
+    public void testParsingUnquotedStrings() throws JSONException {
+        assertParsed("abc", "abc");
+        assertParsed("123abc", "123abc");
+        assertParsed("123e0x", "123e0x");
+        assertParsed("123e", "123e");
+        assertParsed("123ee21", "123ee21");
+        assertParsed("0xFFFFFFFFFFFFFFFFF", "0xFFFFFFFFFFFFFFFFF");
+    }
+
+    /**
+     * Unfortunately the original implementation attempts to figure out what
+     * Java number type best suits an input value.
+     */
+    public void testParsingNumbersThatAreBestRepresentedAsLongs() throws JSONException {
+        assertParsed(9223372036854775807L, "9223372036854775807");
+        assertParsed(9223372036854775806L, "9223372036854775806");
+        assertParsed(-9223372036854775808L, "-9223372036854775808");
+        assertParsed(-9223372036854775807L, "-9223372036854775807");
+    }
+
+    public void testParsingNumbersThatAreBestRepresentedAsIntegers() throws JSONException {
+        assertParsed(0, "0");
+        assertParsed(5, "5");
+        assertParsed(-2147483648, "-2147483648");
+        assertParsed(2147483647, "2147483647");
+    }
+
+    public void testParsingNegativeZero() throws JSONException {
+        assertParsed(0, "-0");
+    }
+
+    public void testParsingIntegersWithAdditionalPrecisionYieldDoubles() throws JSONException {
+        assertParsed(1d, "1.00");
+        assertParsed(1d, "1.0");
+        assertParsed(0d, "0.0");
+        assertParsed(-0d, "-0.0");
+    }
+
+    public void testParsingNumbersThatAreBestRepresentedAsDoubles() throws JSONException {
+        assertParsed(9.223372036854776E18, "9223372036854775808");
+        assertParsed(-9.223372036854776E18, "-9223372036854775809");
+        assertParsed(1.7976931348623157E308, "1.7976931348623157e308");
+        assertParsed(2.2250738585072014E-308, "2.2250738585072014E-308");
+        assertParsed(4.9E-324, "4.9E-324");
+        assertParsed(4.9E-324, "4.9e-324");
+    }
+
+    public void testParsingOctalNumbers() throws JSONException {
+        assertParsed(5, "05");
+        assertParsed(8, "010");
+        assertParsed(1046, "02026");
+    }
+
+    public void testParsingHexNumbers() throws JSONException {
+        assertParsed(5, "0x5");
+        assertParsed(16, "0x10");
+        assertParsed(8230, "0x2026");
+        assertParsed(180150010, "0xABCDEFA");
+        assertParsed(2077093803, "0x7BCDEFAB");
+    }
+
+    public void testParsingLargeHexValues() throws JSONException {
+        assertParsed(Integer.MAX_VALUE, "0x7FFFFFFF");
+        String message = "Hex values are parsed as Strings if their signed " +
+                "value is greater than Integer.MAX_VALUE.";
+        assertParsed(message, 0x80000000L, "0x80000000");
+    }
+
+    public void test64BitHexValues() throws JSONException {
+        assertParsed("Large hex longs shouldn't be yield ints or strings", 
+                -1L, "0xFFFFFFFFFFFFFFFF");
+    }
+
+    public void testParsingWithCommentsAndWhitespace() throws JSONException {
+        assertParsed("baz", "  // foo bar \n baz");
+        assertParsed(5, "  /* foo bar \n baz */ 5");
+        assertParsed(5, "  /* foo bar \n baz */ 5 // quux");
+        assertParsed(5, "  5   ");
+        assertParsed(5, "  5  \r\n\t ");
+        assertParsed(5, "\r\n\t   5 ");
+    }
+
+    public void testParsingArrays() throws JSONException {
+        assertParsed(array(), "[]");
+        assertParsed(array(5, 6, true), "[5,6,true]");
+        assertParsed(array(5, 6, array()), "[5,6,[]]");
+        assertParsed(array(5, 6, 7), "[5;6;7]");
+        assertParsed(array(5, 6, 7), "[5  , 6 \t; \r\n 7\n]");
+        assertParsed(array(5, 6, 7, null), "[5,6,7,]");
+        assertParsed(array(null, null), "[,]");
+        assertParsed(array(5, null, null, null, 5), "[5,,,,5]");
+        assertParsed(array(null, 5), "[,5]");
+        assertParsed(array(null, null, null), "[,,]");
+        assertParsed(array(null, null, null, 5), "[,,,5]");
+    }
+
+    public void testParsingObjects() throws JSONException {
+        assertParsed(object("foo", 5), "{\"foo\": 5}");
+        assertParsed(object("foo", 5), "{foo: 5}");
+        assertParsed(object("foo", 5, "bar", "baz"), "{\"foo\": 5, \"bar\": \"baz\"}");
+        assertParsed(object("foo", 5, "bar", "baz"), "{\"foo\": 5; \"bar\": \"baz\"}");
+        assertParsed(object("foo", 5, "bar", "baz"), "{\"foo\"= 5; \"bar\"= \"baz\"}");
+        assertParsed(object("foo", 5, "bar", "baz"), "{\"foo\"=> 5; \"bar\"=> \"baz\"}");
+        assertParsed(object("foo", object(), "bar", array()), "{\"foo\"=> {}; \"bar\"=> []}");
+        assertParsed(object("foo", object("foo", array(5, 6))), "{\"foo\": {\"foo\": [5, 6]}}");
+        assertParsed(object("foo", object("foo", array(5, 6))), "{\"foo\":\n\t{\t \"foo\":[5,\r6]}}");
+    }
+
+    public void testSyntaxProblemUnterminatedObject() {
+        assertParseFail("{");
+        assertParseFail("{\"foo\"");
+        assertParseFail("{\"foo\":");
+        assertParseFail("{\"foo\":bar");
+        assertParseFail("{\"foo\":bar,");
+        assertParseFail("{\"foo\":bar,\"baz\"");
+        assertParseFail("{\"foo\":bar,\"baz\":");
+        assertParseFail("{\"foo\":bar,\"baz\":true");
+        assertParseFail("{\"foo\":bar,\"baz\":true,");
+    }
+
+    public void testSyntaxProblemEmptyString() {
+        assertParseFail("");
+    }
+
+    public void testSyntaxProblemUnterminatedArray() {
+        assertParseFail("[");
+        assertParseFail("[,");
+        assertParseFail("[,,");
+        assertParseFail("[true");
+        assertParseFail("[true,");
+        assertParseFail("[true,,");
+    }
+
+    public void testSyntaxProblemMalformedObject() {
+        assertParseFail("{:}");
+        assertParseFail("{\"key\":}");
+        assertParseFail("{:true}");
+        assertParseFail("{\"key\":true:}");
+        assertParseFail("{null:true}");
+        assertParseFail("{true:true}");
+        assertParseFail("{0xFF:true}");
+    }
+
+    private void assertParseFail(String malformedJson) {
+        try {
+            new JSONTokener(malformedJson).nextValue();
+            fail("Successfully parsed: \"" + malformedJson + "\"");
+        } catch (JSONException e) {
+        } catch (StackOverflowError e) {
+            fail("Stack overflowed on input: \"" + malformedJson + "\"");
+        }
+    }
+
+    private JSONArray array(Object... elements) {
+        return new JSONArray(Arrays.asList(elements));
+    }
+
+    private JSONObject object(Object... keyValuePairs) throws JSONException {
+        JSONObject result = new JSONObject();
+        for (int i = 0; i < keyValuePairs.length; i+=2) {
+            result.put((String) keyValuePairs[i], keyValuePairs[i+1]);
+        }
+        return result;
+    }
+
+    private void assertParsed(String message, Object expected, String json) throws JSONException {
+        Object actual = new JSONTokener(json).nextValue();
+        actual = canonicalize(actual);
+        expected = canonicalize(expected);
+        assertEquals("For input \"" + json + "\" " + message, expected, actual);
+    }
+
+    private void assertParsed(Object expected, String json) throws JSONException {
+        assertParsed("", expected, json);
+    }
+
+    /**
+     * Since they don't implement equals or hashCode properly, this recursively
+     * replaces JSONObjects with an equivalent HashMap, and JSONArrays with the
+     * equivalent ArrayList.
+     */
+    private Object canonicalize(Object input) throws JSONException {
+        if (input instanceof JSONArray) {
+            JSONArray array = (JSONArray) input;
+            List<Object> result = new ArrayList<Object>();
+            for (int i = 0; i < array.length(); i++) {
+                result.add(canonicalize(array.opt(i)));
+            }
+            return result;
+        } else if (input instanceof JSONObject) {
+            JSONObject object = (JSONObject) input;
+            Map<String, Object> result = new HashMap<String, Object>();
+            for (Iterator<?> i = object.keys(); i.hasNext(); ) {
+                String key = (String) i.next();
+                result.put(key, canonicalize(object.get(key)));
+            }
+            return result;
+        } else {
+            return input;
+        }
+    }
+}
diff --git a/libcore/json/src/test/java/org/json/SelfUseTest.java b/libcore/json/src/test/java/org/json/SelfUseTest.java
new file mode 100644
index 0000000..15a0824
--- /dev/null
+++ b/libcore/json/src/test/java/org/json/SelfUseTest.java
@@ -0,0 +1,229 @@
+/*
+ * 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 org.json;
+
+import junit.framework.TestCase;
+
+/**
+ * These tests checks self use calls. For the most part we doesn't attempt to
+ * cover self-use, except in those cases where our clean room implementation
+ * does it.
+ *
+ * <p>This black box test was written without inspecting the non-free org.json
+ * sourcecode.
+ */
+public class SelfUseTest extends TestCase {
+
+    private int objectPutCalls = 0;
+    private int objectGetCalls = 0;
+    private int objectOptCalls = 0;
+    private int objectOptTypeCalls = 0;
+    private int arrayPutCalls = 0;
+    private int arrayGetCalls = 0;
+    private int arrayOptCalls = 0;
+    private int arrayOptTypeCalls = 0;
+    private int tokenerNextCalls = 0;
+    private int tokenerNextValueCalls = 0;
+
+    private final JSONObject object = new JSONObject() {
+        @Override public JSONObject put(String name, Object value) throws JSONException {
+            objectPutCalls++;
+            return super.put(name, value);
+        }
+        @Override public Object get(String name) throws JSONException {
+            objectGetCalls++;
+            return super.get(name);
+        }
+        @Override public Object opt(String name) {
+            objectOptCalls++;
+            return super.opt(name);
+        }
+        @Override public boolean optBoolean(String key, boolean defaultValue) {
+            objectOptTypeCalls++;
+            return super.optBoolean(key, defaultValue);
+        }
+        @Override public double optDouble(String key, double defaultValue) {
+            objectOptTypeCalls++;
+            return super.optDouble(key, defaultValue);
+        }
+        @Override public int optInt(String key, int defaultValue) {
+            objectOptTypeCalls++;
+            return super.optInt(key, defaultValue);
+        }
+        @Override public long optLong(String key, long defaultValue) {
+            objectOptTypeCalls++;
+            return super.optLong(key, defaultValue);
+        }
+        @Override public String optString(String key, String defaultValue) {
+            objectOptTypeCalls++;
+            return super.optString(key, defaultValue);
+        }
+    };
+
+    private final JSONArray array = new JSONArray() {
+        @Override public JSONArray put(int index, Object value) throws JSONException {
+            arrayPutCalls++;
+            return super.put(index, value);
+        }
+        @Override public Object get(int index) throws JSONException {
+            arrayGetCalls++;
+            return super.get(index);
+        }
+        @Override public Object opt(int index) {
+            arrayOptCalls++;
+            return super.opt(index);
+        }
+        @Override public boolean optBoolean(int index, boolean fallback) {
+            arrayOptTypeCalls++;
+            return super.optBoolean(index, fallback);
+        }
+        @Override public double optDouble(int index, double fallback) {
+            arrayOptTypeCalls++;
+            return super.optDouble(index, fallback);
+        }
+        @Override public long optLong(int index, long fallback) {
+            arrayOptTypeCalls++;
+            return super.optLong(index, fallback);
+        }
+        @Override public String optString(int index, String fallback) {
+            arrayOptTypeCalls++;
+            return super.optString(index, fallback);
+        }
+        @Override public int optInt(int index, int fallback) {
+            arrayOptTypeCalls++;
+            return super.optInt(index, fallback);
+        }
+    };
+
+    private final JSONTokener tokener = new JSONTokener("{\"foo\": [true]}") {
+        @Override public char next() {
+            tokenerNextCalls++;
+            return super.next();
+        }
+        @Override public Object nextValue() throws JSONException {
+            tokenerNextValueCalls++;
+            return super.nextValue();
+        }
+    };
+
+
+    public void testObjectPut() throws JSONException {
+        object.putOpt("foo", "bar");
+        assertEquals(1, objectPutCalls);
+    }
+
+    public void testObjectAccumulate() throws JSONException {
+        object.accumulate("foo", "bar");
+        assertEquals(1, objectPutCalls);
+    }
+
+    public void testObjectGetBoolean() throws JSONException {
+        object.put("foo", "true");
+        object.getBoolean("foo");
+        assertEquals(1, objectGetCalls);
+    }
+
+    public void testObjectOptType() throws JSONException {
+        object.optBoolean("foo");
+        assertEquals(1, objectOptCalls);
+        assertEquals(1, objectOptTypeCalls);
+        object.optDouble("foo");
+        assertEquals(2, objectOptCalls);
+        assertEquals(2, objectOptTypeCalls);
+        object.optInt("foo");
+        assertEquals(3, objectOptCalls);
+        assertEquals(3, objectOptTypeCalls);
+        object.optLong("foo");
+        assertEquals(4, objectOptCalls);
+        assertEquals(4, objectOptTypeCalls);
+        object.optString("foo");
+        assertEquals(5, objectOptCalls);
+        assertEquals(5, objectOptTypeCalls);
+    }
+
+    public void testToJSONArray() throws JSONException {
+        object.put("foo", 5);
+        object.put("bar", 10);
+        array.put("foo");
+        array.put("baz");
+        array.put("bar");
+        object.toJSONArray(array);
+        assertEquals(3, arrayOptCalls);
+        assertEquals(0, arrayOptTypeCalls);
+        assertEquals(3, objectOptCalls);
+        assertEquals(0, objectOptTypeCalls);
+    }
+
+    public void testPutAtIndex() throws JSONException {
+        array.put(10, false);
+        assertEquals(1, arrayPutCalls);
+    }
+
+    public void testIsNull() {
+        array.isNull(5);
+        assertEquals(1, arrayOptCalls);
+    }
+
+    public void testArrayGetType() throws JSONException {
+        array.put(true);
+        array.getBoolean(0);
+        assertEquals(1, arrayGetCalls);
+    }
+
+    public void testArrayOptType() throws JSONException {
+        array.optBoolean(3);
+        assertEquals(1, arrayOptCalls);
+        assertEquals(1, arrayOptTypeCalls);
+        array.optDouble(3);
+        assertEquals(2, arrayOptCalls);
+        assertEquals(2, arrayOptTypeCalls);
+        array.optInt(3);
+        assertEquals(3, arrayOptCalls);
+        assertEquals(3, arrayOptTypeCalls);
+        array.optLong(3);
+        assertEquals(4, arrayOptCalls);
+        assertEquals(4, arrayOptTypeCalls);
+        array.optString(3);
+        assertEquals(5, arrayOptCalls);
+        assertEquals(5, arrayOptTypeCalls);
+    }
+
+    public void testToJSONObject() throws JSONException {
+        array.put("foo");
+        array.put("baz");
+        array.put("bar");
+        JSONArray values = new JSONArray();
+        values.put(5.5d);
+        values.put(11d);
+        values.put(30);
+        values.toJSONObject(array);
+        assertEquals(3, arrayOptCalls);
+        assertEquals(0, arrayOptTypeCalls);
+    }
+
+    public void testNextExpecting() throws JSONException {
+        tokener.next('{');
+        assertEquals(1, tokenerNextCalls);
+        tokener.next('\"');
+        assertEquals(2, tokenerNextCalls);
+    }
+
+    public void testNextValue() throws JSONException {
+        tokener.nextValue();
+        assertEquals(4, tokenerNextValueCalls);
+    }
+}
diff --git a/libcore/luni-kernel/src/main/java/java/lang/Class.java b/libcore/luni-kernel/src/main/java/java/lang/Class.java
index 571f5b1..35e47bc 100644
--- a/libcore/luni-kernel/src/main/java/java/lang/Class.java
+++ b/libcore/luni-kernel/src/main/java/java/lang/Class.java
@@ -117,8 +117,6 @@
  * <li>{@code [Ljava/lang/String;} representing the {@code String[]} type</li>
  * <li>{@code [[[C} representing the {@code char[][][]} type (three dimensions!)</li>
  * </ul>
- * 
- * @since Android 1.0
  */
 public final class Class<T> implements Serializable, AnnotatedElement, GenericDeclaration, Type {
 
@@ -1425,8 +1423,7 @@
      *             if a security manager exists and it does not allow creating
      *             new instances.
      */
-    public T newInstance() throws IllegalAccessException,
-            InstantiationException {
+    public T newInstance() throws InstantiationException, IllegalAccessException {
         checkPublicMemberAccess();        
         return newInstanceImpl();
     }
diff --git a/libcore/luni-kernel/src/main/java/java/lang/ClassLoader.java b/libcore/luni-kernel/src/main/java/java/lang/ClassLoader.java
index 3c2e911..17206aa 100644
--- a/libcore/luni-kernel/src/main/java/java/lang/ClassLoader.java
+++ b/libcore/luni-kernel/src/main/java/java/lang/ClassLoader.java
@@ -1040,7 +1040,7 @@
 
     static BootClassLoader instance;
 
-    public static BootClassLoader getInstance() {
+    public static synchronized BootClassLoader getInstance() {
         if (instance == null) {
             instance = new BootClassLoader();
         }
diff --git a/libcore/luni-kernel/src/main/java/java/lang/Object.java b/libcore/luni-kernel/src/main/java/java/lang/Object.java
index 4fef609..5250871 100644
--- a/libcore/luni-kernel/src/main/java/java/lang/Object.java
+++ b/libcore/luni-kernel/src/main/java/java/lang/Object.java
@@ -148,10 +148,10 @@
     }
 
     /**
-     * Returns the unique instance of {@link Class} which represents this
+     * Returns the unique instance of {@link Class} that represents this
      * object's class. Note that {@code getClass()} is a special case in that it
      * actually returns {@code Class<? extends Foo>} where {@code Foo} is the
-     * erasure of the type of expression {@code getClass()} was called upon.
+     * erasure of the type of the expression {@code getClass()} was called upon.
      * <p>
      * As an example, the following code actually compiles, although one might
      * think it shouldn't:
@@ -162,7 +162,6 @@
      * </pre>
      * 
      * @return this object's {@code Class} instance.
-     * @since Android 1.0
      */
     public final native Class<? extends Object> getClass();
 
diff --git a/libcore/luni-kernel/src/main/java/java/lang/Package.java b/libcore/luni-kernel/src/main/java/java/lang/Package.java
index 4d98959..58cee36 100644
--- a/libcore/luni-kernel/src/main/java/java/lang/Package.java
+++ b/libcore/luni-kernel/src/main/java/java/lang/Package.java
@@ -79,11 +79,11 @@
      * @since Android 1.0
      */
     @SuppressWarnings("unchecked")
-    public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
+    public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
         Annotation[] list = getAnnotations();
         for (int i = 0; i < list.length; i++) {
             if (annotationType.isInstance(list[i])) {
-                return (T)list[i];
+                return (A) list[i];
             }
         }
         
diff --git a/libcore/luni-kernel/src/main/java/java/lang/reflect/Array.java b/libcore/luni-kernel/src/main/java/java/lang/reflect/Array.java
index d633e69..8c01054 100644
--- a/libcore/luni-kernel/src/main/java/java/lang/reflect/Array.java
+++ b/libcore/luni-kernel/src/main/java/java/lang/reflect/Array.java
@@ -76,19 +76,19 @@
             return ((boolean[]) array)[index] ? Boolean.TRUE : Boolean.FALSE;
         
         if (array instanceof byte[])
-            return new Byte(((byte[]) array)[index]);
+            return Byte.valueOf(((byte[]) array)[index]);
         
         if (array instanceof char[])
-            return new Character(((char[]) array)[index]);
+            return Character.valueOf(((char[]) array)[index]);
         
         if (array instanceof short[])
-            return new Short(((short[]) array)[index]);
+            return Short.valueOf(((short[]) array)[index]);
         
         if (array instanceof int[])
-            return new Integer(((int[]) array)[index]);
+            return Integer.valueOf(((int[]) array)[index]);
         
         if (array instanceof long[])
-            return new Long(((long[]) array)[index]);
+            return Long.valueOf(((long[]) array)[index]);
         
         if (array instanceof float[])
             return new Float(((float[]) array)[index]);
diff --git a/libcore/luni/src/main/java/java/io/File.java b/libcore/luni/src/main/java/java/io/File.java
index 2910f91..a53b3c1 100644
--- a/libcore/luni/src/main/java/java/io/File.java
+++ b/libcore/luni/src/main/java/java/io/File.java
@@ -311,6 +311,33 @@
     }
 
     /**
+     * Tests whether or not this process is allowed to execute this file.
+     * Note that this is a best-effort result; the only way to be certain is
+     * to actually attempt the operation.
+     *
+     * @return {@code true} if this file can be executed, {@code false} otherwise.
+     * @throws SecurityException
+     *             If a security manager exists and
+     *             SecurityManager.checkExec(java.lang.String) disallows read
+     *             permission to this file object
+     * @see java.lang.SecurityManager#checkExec(String)
+     *
+     * @since 1.6
+     * @hide
+     */
+    public boolean canExecute() {
+        if (path.length() == 0) {
+            return false;
+        }
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkExec(path); // Seems bogus, but this is what the RI does.
+        }
+        return canExecuteImpl(pathBytes);
+    }
+    private native boolean canExecuteImpl(byte[] filePath);
+
+    /**
      * Indicates whether the current context is allowed to read from this file.
      *
      * @return {@code true} if this file can be read, {@code false} otherwise.
@@ -326,10 +353,9 @@
         if (security != null) {
             security.checkRead(path);
         }
-        return isReadableImpl(pathBytes);
+        return canReadImpl(pathBytes);
     }
-
-    private native boolean isReadableImpl(byte[] filePath);
+    private native boolean canReadImpl(byte[] filePath);
 
     /**
      * Indicates whether the current context is allowed to write to this file.
@@ -348,10 +374,9 @@
         if (security != null) {
             security.checkWrite(path);
         }
-        return isWritableImpl(pathBytes);
+        return canWriteImpl(pathBytes);
     }
-
-    private native boolean isWritableImpl(byte[] filePath);
+    private native boolean canWriteImpl(byte[] filePath);
 
     /**
      * Returns the relative sort ordering of the paths for this file and the
@@ -756,7 +781,7 @@
      * Indicates if this file's pathname is absolute. Whether a pathname is
      * absolute is platform specific. On Android, absolute paths start with
      * the character '/'.
-     * 
+     *
      * @return {@code true} if this file's pathname is absolute, {@code false}
      *         otherwise.
      * @see #getPath
@@ -887,16 +912,38 @@
     private native boolean setLastModifiedImpl(byte[] path, long time);
 
     /**
-     * Marks this file or directory to be read-only as defined by the operating
-     * system.
+     * Equivalent to setWritable(false, false).
      *
-     * @return {@code true} if the operation is successful, {@code false}
-     *         otherwise.
-     * @throws SecurityException
-     *             if a {@code SecurityManager} is installed and it denies write
-     *             access to this file.
+     * @see #setWritable(boolean, boolean)
      */
     public boolean setReadOnly() {
+        return setWritable(false, false);
+    }
+
+    /**
+     * Manipulates the execute permissions for the abstract path designated by
+     * this file.
+     *
+     * @param executable
+     *            To allow execute permission if true, otherwise disallow
+     * @param ownerOnly
+     *            To manipulate execute permission only for owner if true,
+     *            otherwise for everyone. The manipulation will apply to
+     *            everyone regardless of this value if the underlying system
+     *            does not distinguish owner and other users.
+     * @return true if and only if the operation succeeded. If the user does not
+     *         have permission to change the access permissions of this abstract
+     *         pathname the operation will fail. If the underlying file system
+     *         does not support execute permission and the value of executable
+     *         is false, this operation will fail.
+     * @throws SecurityException -
+     *             If a security manager exists and
+     *             SecurityManager.checkWrite(java.lang.String) disallows write
+     *             permission to this file object
+     * @since 1.6
+     * @hide
+     */
+    public boolean setExecutable(boolean executable, boolean ownerOnly) {
         if (path.length() == 0) {
             return false;
         }
@@ -904,10 +951,141 @@
         if (security != null) {
             security.checkWrite(path);
         }
-        return setReadOnlyImpl(pathBytes);
+        return setExecutableImpl(pathBytes, executable, ownerOnly);
     }
 
-    private native boolean setReadOnlyImpl(byte[] path);
+    /**
+     * Equivalent to setExecutable(executable, true).
+     *
+     * @param executable
+     *            To allow execute permission if true, otherwise disallow
+     * @return true if and only if the operation succeeded. If the user does not
+     *         have permission to change the access permissions of this abstract
+     *         pathname the operation will fail. If the underlying file system
+     *         does not support execute permission and the value of executable
+     *         is false, this operation will fail.
+     * @throws SecurityException -
+     *             If a security manager exists and
+     *             SecurityManager.checkWrite(java.lang.String) disallows write
+     *             permission to this file object
+     * @since 1.6
+     * @hide
+     */
+    public boolean setExecutable(boolean executable) {
+        return setExecutable(executable, true);
+    }
+
+    private native boolean setExecutableImpl(byte[] path, boolean executable, boolean ownerOnly);
+
+    /**
+     * Manipulates the read permissions for the abstract path designated by this
+     * file.
+     *
+     * @param readable
+     *            To allow read permission if true, otherwise disallow
+     * @param ownerOnly
+     *            To manipulate read permission only for owner if true,
+     *            otherwise for everyone. The manipulation will apply to
+     *            everyone regardless of this value if the underlying system
+     *            does not distinguish owner and other users.
+     * @return true if and only if the operation succeeded. If the user does not
+     *         have permission to change the access permissions of this abstract
+     *         pathname the operation will fail. If the underlying file system
+     *         does not support read permission and the value of readable is
+     *         false, this operation will fail.
+     * @throws SecurityException -
+     *             If a security manager exists and
+     *             SecurityManager.checkWrite(java.lang.String) disallows write
+     *             permission to this file object
+     * @since 1.6
+     * @hide
+     */
+    public boolean setReadable(boolean readable, boolean ownerOnly) {
+        if (path.length() == 0) {
+            return false;
+        }
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkWrite(path);
+        }
+        return setReadableImpl(pathBytes, readable, ownerOnly);
+    }
+
+    /**
+     * Equivalent to setReadable(readable, true).
+     *
+     * @param readable
+     *            To allow read permission if true, otherwise disallow
+     * @return true if and only if the operation succeeded. If the user does not
+     *         have permission to change the access permissions of this abstract
+     *         pathname the operation will fail. If the underlying file system
+     *         does not support read permission and the value of readable is
+     *         false, this operation will fail.
+     * @throws SecurityException -
+     *             If a security manager exists and
+     *             SecurityManager.checkWrite(java.lang.String) disallows write
+     *             permission to this file object
+     * @since 1.6
+     * @hide
+     */
+    public boolean setReadable(boolean readable) {
+        return setReadable(readable, true);
+    }
+
+    private native boolean setReadableImpl(byte[] path, boolean readable, boolean ownerOnly);
+
+    /**
+     * Manipulates the write permissions for the abstract path designated by this
+     * file.
+     *
+     * @param writable
+     *            To allow write permission if true, otherwise disallow
+     * @param ownerOnly
+     *            To manipulate write permission only for owner if true,
+     *            otherwise for everyone. The manipulation will apply to
+     *            everyone regardless of this value if the underlying system
+     *            does not distinguish owner and other users.
+     * @return true if and only if the operation succeeded. If the user does not
+     *         have permission to change the access permissions of this abstract
+     *         pathname the operation will fail.
+     * @throws SecurityException -
+     *             If a security manager exists and
+     *             SecurityManager.checkWrite(java.lang.String) disallows write
+     *             permission to this file object
+     * @since 1.6
+     * @hide
+     */
+    public boolean setWritable(boolean writable, boolean ownerOnly) {
+        if (path.length() == 0) {
+            return false;
+        }
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkWrite(path);
+        }
+        return setWritableImpl(pathBytes, writable, ownerOnly);
+    }
+
+    /**
+     * Equivalent to setWritable(writable, true).
+     *
+     * @param writable
+     *            To allow write permission if true, otherwise disallow
+     * @return true if and only if the operation succeeded. If the user does not
+     *         have permission to change the access permissions of this abstract
+     *         pathname the operation will fail.
+     * @throws SecurityException -
+     *             If a security manager exists and
+     *             SecurityManager.checkWrite(java.lang.String) disallows write
+     *             permission to this file object
+     * @since 1.6
+     * @hide
+     */
+    public boolean setWritable(boolean writable) {
+        return setWritable(writable, true);
+    }
+
+    private native boolean setWritableImpl(byte[] path, boolean writable, boolean ownerOnly);
 
     /**
      * Returns the length of this file in bytes.
@@ -1308,7 +1486,10 @@
      * @return a URL for this file.
      * @throws java.net.MalformedURLException
      *             if the path cannot be transformed into a URL.
+     * @deprecated use {@link #toURI} and {@link java.net.URI#toURL} to get
+     * correct escaping of illegal characters.
      */
+    @Deprecated
     @SuppressWarnings("nls")
     public URL toURL() throws java.net.MalformedURLException {
         String name = getAbsoluteName();
@@ -1343,10 +1524,67 @@
         stream.writeChar(separatorChar);
     }
 
-    private void readObject(ObjectInputStream stream) throws IOException,
-            ClassNotFoundException {
+    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
         stream.defaultReadObject();
         char inSeparator = stream.readChar();
         init(path.replace(inSeparator, separatorChar));
     }
+
+    /**
+     * Returns the total size in bytes of the partition containing this path.
+     * Returns 0 if this path does not exist.
+     *
+     * @since 1.6
+     * @hide
+     */
+    public long getTotalSpace() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkPermission(new RuntimePermission("getFileSystemAttributes"));
+        }
+        return getTotalSpaceImpl(pathBytes);
+    }
+    private native long getTotalSpaceImpl(byte[] filePath);
+
+    /**
+     * Returns the number of usable free bytes on the partition containing this path.
+     * Returns 0 if this path does not exist.
+     *
+     * <p>Note that this is likely to be an optimistic over-estimate and should not
+     * be taken as a guarantee your application can actually write this many bytes.
+     * On Android (and other Unix-based systems), this method returns the number of free bytes
+     * available to non-root users, regardless of whether you're actually running as root,
+     * and regardless of any quota or other restrictions that might apply to the user.
+     * (The {@code getFreeSpace} method returns the number of bytes potentially available to root.)
+     *
+     * @since 1.6
+     * @hide
+     */
+    public long getUsableSpace() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkPermission(new RuntimePermission("getFileSystemAttributes"));
+        }
+        return getUsableSpaceImpl(pathBytes);
+    }
+    private native long getUsableSpaceImpl(byte[] filePath);
+
+    /**
+     * Returns the number of free bytes on the partition containing this path.
+     * Returns 0 if this path does not exist.
+     *
+     * <p>Note that this is likely to be an optimistic over-estimate and should not
+     * be taken as a guarantee your application can actually write this many bytes.
+     *
+     * @since 1.6
+     * @hide
+     */
+    public long getFreeSpace() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkPermission(new RuntimePermission("getFileSystemAttributes"));
+        }
+        return getFreeSpaceImpl(pathBytes);
+    }
+    private native long getFreeSpaceImpl(byte[] filePath);
 }
diff --git a/libcore/luni/src/main/java/java/io/FileInputStream.java b/libcore/luni/src/main/java/java/io/FileInputStream.java
index 20f7eae..6a65395 100644
--- a/libcore/luni/src/main/java/java/io/FileInputStream.java
+++ b/libcore/luni/src/main/java/java/io/FileInputStream.java
@@ -146,33 +146,7 @@
     @Override
     public int available() throws IOException {
         openCheck();
-
-        // BEGIN android-added
-
-        // Android always uses the ioctl() method of determining bytes
-        // available. See the long discussion in
-        // org_apache_harmony_luni_platform_OSFileSystem.cpp about its
-        // use.
-
-        return fileSystem.ioctlAvailable(fd.descriptor);
-        // END android-added
-
-        // BEGIN android-deleted
-        // synchronized (repositioningLock) {
-        //     // stdin requires special handling
-        //     if (fd == FileDescriptor.in) {
-        //         return (int) fileSystem.ttyAvailable();
-        //     }
-        //
-        //     long currentPosition = fileSystem.seek(fd.descriptor, 0L,
-        //             IFileSystem.SEEK_CUR);
-        //     long endOfFilePosition = fileSystem.seek(fd.descriptor, 0L,
-        //             IFileSystem.SEEK_END);
-        //     fileSystem.seek(fd.descriptor, currentPosition,
-        //             IFileSystem.SEEK_SET);
-        //     return (int) (endOfFilePosition - currentPosition);
-        // }
-        // END android-deleted
+        return fileSystem.ioctlAvailable(fd);
     }
 
     /**
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiUnavailableException.java b/libcore/luni/src/main/java/java/io/IOError.java
similarity index 65%
rename from libcore-disabled/sound/src/main/java/javax/sound/midi/MidiUnavailableException.java
rename to libcore/luni/src/main/java/java/io/IOError.java
index bd50af5..d47b93c 100644
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiUnavailableException.java
+++ b/libcore/luni/src/main/java/java/io/IOError.java
@@ -15,16 +15,24 @@
  *  limitations under the License.
  */
 
-package javax.sound.midi;
+package java.io;
 
-public class MidiUnavailableException extends Exception {
-    private static final long serialVersionUID = 6093809578628944323L;
+/**
+ * This error is thrown when a severe I/O error has happened.
+ * 
+ * @since 1.6
+ * @hide
+ */
+public class IOError extends Error {
+    private static final long serialVersionUID = 67100927991680413L;
 
-    public MidiUnavailableException() {
-        super();
-    }
-
-    public MidiUnavailableException(String message) {
-        super(message);
+    /**
+     * Constructs a new instance with its cause filled in.
+     * 
+     * @param cause
+     *            The detail cause for the error.
+     */
+    public IOError(Throwable cause) {
+        super(cause);
     }
 }
diff --git a/libcore/luni/src/main/java/java/io/IOException.java b/libcore/luni/src/main/java/java/io/IOException.java
index 24cea9f..fbd2048 100644
--- a/libcore/luni/src/main/java/java/io/IOException.java
+++ b/libcore/luni/src/main/java/java/io/IOException.java
@@ -37,11 +37,38 @@
     /**
      * Constructs a new {@code IOException} with its stack trace and detail
      * message filled in.
-     * 
+     *
      * @param detailMessage
      *            the detail message for this exception.
      */
     public IOException(String detailMessage) {
         super(detailMessage);
     }
+
+    /**
+     * Constructs a new instance of this class with detail message and cause
+     * filled in.
+     *
+     * @param message
+     *            The detail message for the exception.
+     * @param cause
+     *            The detail cause for the exception.
+     * @since 1.6
+     * @hide
+     */
+    public IOException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new instance of this class with its detail cause filled in.
+     *
+     * @param cause
+     *            The detail cause for the exception.
+     * @since 1.6
+     * @hide
+     */
+    public IOException(Throwable cause) {
+        super(cause == null ? null : cause.toString(), cause);
+    }
 }
diff --git a/libcore/luni/src/main/java/java/lang/Double.java b/libcore/luni/src/main/java/java/lang/Double.java
index d6ad58e..a4a9dc2 100644
--- a/libcore/luni/src/main/java/java/lang/Double.java
+++ b/libcore/luni/src/main/java/java/lang/Double.java
@@ -51,16 +51,42 @@
     public static final double NaN = 0.0 / 0.0;
 
     /**
-     * Constant for the Positive Infinity value of the {@code double} type.
+     * Constant for the positive infinity value of the {@code double} type.
      */
     public static final double POSITIVE_INFINITY = 1.0 / 0.0;
 
     /**
-     * Constant for the Negative Infinity value of the {@code double} type.
+     * Constant for the negative infinity value of the {@code double} type.
      */
     public static final double NEGATIVE_INFINITY = -1.0 / 0.0;
 
     /**
+     * Constant for the smallest positive normal value of the {@code double} type.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static final double MIN_NORMAL = 2.2250738585072014E-308;
+
+    /**
+     * Maximum exponent that a finite value of the {@code double} type may have.
+     * Equal to {@code Math.getExponent(Double.MAX_VALUE)}.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static final int MAX_EXPONENT = 1023;
+
+    /**
+     * Minimum exponent that a normal value of the {@code double} type may have.
+     * Equal to {@code Math.getExponent(Double.MIN_NORMAL)}.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static final int MIN_EXPONENT = -1022;
+
+    /**
      * The {@link Class} object that represents the primitive type {@code
      * double}.
      *
@@ -174,11 +200,13 @@
     }
 
     /**
-     * Compares this object with the specified object and indicates if they are
-     * equal. In order to be equal, {@code object} must be an instance of
-     * {@code Double} and the bit pattern of its double value is the same as
-     * this object's.
-     *
+     * Tests this double for equality with {@code object}.
+     * To be equal, {@code object} must be an instance of {@code Double} and
+     * {@code doubleToLongBits} must give the same value for both objects.
+     * 
+     * <p>Note that, unlike {@code ==}, {@code -0.0} and {@code +0.0} compare
+     * unequal, and {@code NaN}s compare equal by this method.
+     * 
      * @param object
      *            the object to compare this double with.
      * @return {@code true} if the specified object is equal to this
diff --git a/libcore/luni/src/main/java/java/lang/Enum.java b/libcore/luni/src/main/java/java/lang/Enum.java
index e2ee32a..a59010c 100644
--- a/libcore/luni/src/main/java/java/lang/Enum.java
+++ b/libcore/luni/src/main/java/java/lang/Enum.java
@@ -191,6 +191,16 @@
         // END android-changed
     }
 
+    /**
+     * Enum types may not have finalizers.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    @Override
+    protected final void finalize() {
+    }
+
     /*
      * Helper to invoke the values() static method on T and answer the result.
      * Returns null if there is a problem.
diff --git a/libcore/luni/src/main/java/java/lang/Float.java b/libcore/luni/src/main/java/java/lang/Float.java
index 92b1731..2d2140d 100644
--- a/libcore/luni/src/main/java/java/lang/Float.java
+++ b/libcore/luni/src/main/java/java/lang/Float.java
@@ -48,16 +48,42 @@
     public static final float NaN = 0.0f / 0.0f;
 
     /**
-     * Constant for the Positive Infinity value of the {@code float} type.
+     * Constant for the positive infinity value of the {@code float} type.
      */
     public static final float POSITIVE_INFINITY = 1.0f / 0.0f;
 
     /**
-     * Constant for the Negative Infinity value of the {@code float} type.
+     * Constant for the negative infinity value of the {@code float} type.
      */
     public static final float NEGATIVE_INFINITY = -1.0f / 0.0f;
 
     /**
+     * Constant for the smallest positive normal value of the {@code float} type.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static final float MIN_NORMAL = 1.1754943508222875E-38f;
+
+    /**
+     * Maximum exponent that a finite value of the {@code float} type may have.
+     * Equal to {@code Math.getExponent(Float.MAX_VALUE)}.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static final int MAX_EXPONENT = 127;
+
+    /**
+     * Minimum exponent that a normal value of the {@code float} type may have.
+     * Equal to {@code Math.getExponent(Float.MIN_NORMAL)}.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static final int MIN_EXPONENT = -126;
+
+    /**
      * The {@link Class} object that represents the primitive type {@code
      * float}.
      *
@@ -144,10 +170,13 @@
     }
 
     /**
-     * Compares this instance with the specified object and indicates if they
-     * are equal. In order to be equal, {@code object} must be an instance of
-     * {@code Float} and have the same float value as this object.
-     *
+     * Tests this double for equality with {@code object}.
+     * To be equal, {@code object} must be an instance of {@code Float} and
+     * {@code floatToIntBits} must give the same value for both objects.
+     * 
+     * <p>Note that, unlike {@code ==}, {@code -0.0} and {@code +0.0} compare
+     * unequal, and {@code NaN}s compare equal by this method.
+     * 
      * @param object
      *            the object to compare this float with.
      * @return {@code true} if the specified object is equal to this
diff --git a/libcore/luni/src/main/java/java/lang/Integer.java b/libcore/luni/src/main/java/java/lang/Integer.java
index 34b9c16..63cd615 100644
--- a/libcore/luni/src/main/java/java/lang/Integer.java
+++ b/libcore/luni/src/main/java/java/lang/Integer.java
@@ -610,15 +610,20 @@
     }
 
     /**
-     * Converts the specified integer into a string representation based on the
+     * Converts the specified signed integer into a string representation based on the
      * specified radix. The returned string is a concatenation of a minus sign
      * if the number is negative and characters from '0' to '9' and 'a' to 'z',
      * depending on the radix. If {@code radix} is not in the interval defined
      * by {@code Character.MIN_RADIX} and {@code Character.MAX_RADIX} then 10 is
      * used as the base for the conversion.
+     * 
+     * <p>This method treats its argument as signed. If you want to convert an
+     * unsigned value to one of the common non-decimal bases, you may find
+     * {@link #toBinaryString}, {@code #toHexString}, or {@link #toOctalString}
+     * more convenient.
      *
      * @param i
-     *            the integer to convert.
+     *            the signed integer to convert.
      * @param radix
      *            the base to use for the conversion.
      * @return the string representation of {@code i}.
diff --git a/libcore/luni/src/main/java/java/lang/Iterable.java b/libcore/luni/src/main/java/java/lang/Iterable.java
index 31883fb..193fb7b 100644
--- a/libcore/luni/src/main/java/java/lang/Iterable.java
+++ b/libcore/luni/src/main/java/java/lang/Iterable.java
@@ -19,8 +19,8 @@
 import java.util.Iterator;
 
 /**
- * Objects of classes that implement this interface can be used within a
- * {@code foreach} statement.
+ * Instances of classes that implement this interface can be used with
+ * the enhanced for loop.
  *
  * @since 1.5
  */
diff --git a/libcore/luni/src/main/java/java/lang/Long.java b/libcore/luni/src/main/java/java/lang/Long.java
index 1c52896..2cc4cd7 100644
--- a/libcore/luni/src/main/java/java/lang/Long.java
+++ b/libcore/luni/src/main/java/java/lang/Long.java
@@ -583,15 +583,20 @@
     }
 
     /**
-     * Converts the specified long value into a string representation based on
+     * Converts the specified signed long value into a string representation based on
      * the specified radix. The returned string is a concatenation of a minus
      * sign if the number is negative and characters from '0' to '9' and 'a' to
      * 'z', depending on the radix. If {@code radix} is not in the interval
      * defined by {@code Character.MIN_RADIX} and {@code Character.MAX_RADIX}
      * then 10 is used as the base for the conversion.
+     * 
+     * <p>This method treats its argument as signed. If you want to convert an
+     * unsigned value to one of the common non-decimal bases, you may find
+     * {@link #toBinaryString}, {@code #toHexString}, or {@link #toOctalString}
+     * more convenient.
      *
      * @param v
-     *            the long to convert.
+     *            the signed long to convert.
      * @param radix
      *            the base to use for the conversion.
      * @return the string representation of {@code v}.
diff --git a/libcore/luni/src/main/java/java/lang/Math.java b/libcore/luni/src/main/java/java/lang/Math.java
index f7b49b2..26019ec 100644
--- a/libcore/luni/src/main/java/java/lang/Math.java
+++ b/libcore/luni/src/main/java/java/lang/Math.java
@@ -22,7 +22,30 @@
  * functions, hyperbolic functions, exponential, logarithms, etc.
  */
 public final class Math {
+    private static final int FLOAT_EXPONENT_BIAS = 127;
 
+    private static final int FLOAT_EXPONENT_MASK = 0x7F800000;
+
+    private static final int DOUBLE_NON_MANTISSA_BITS = 12;
+
+    private static final int DOUBLE_MANTISSA_BITS = 52;
+
+    private static final int FLOAT_NON_MANTISSA_BITS = 9;
+
+    private static final int FLOAT_MANTISSA_BITS = 23;
+
+    private static final int DOUBLE_EXPONENT_BIAS = 1023;
+
+    private static final long DOUBLE_EXPONENT_MASK = 0x7ff0000000000000L;
+
+    private static final int FLOAT_MANTISSA_MASK = 0x007fffff;
+
+    private static final int FLOAT_SIGN_MASK = 0x80000000;
+
+    private static final long DOUBLE_MANTISSA_MASK = 0x000fffffffffffffL;
+
+    private static final long DOUBLE_SIGN_MASK = 0x8000000000000000L;
+    
     /**
      * The double value closest to e, the base of the natural logarithm.
      */
@@ -497,7 +520,7 @@
             return Double.NaN;
         }
         /* max(+0.0,-0.0) == +0.0 */
-        /* 0 == Double.doubleToRawLongBits(0.0d) */
+        /* Double.doubleToRawLongBits(0.0d) == 0 */
         if (Double.doubleToRawLongBits(d1) != 0) {
             return d2;
         }
@@ -534,7 +557,7 @@
             return Float.NaN;
         }
         /* max(+0.0,-0.0) == +0.0 */
-        /* 0 == Float.floatToRawIntBits(0.0f) */
+        /* Float.floatToRawIntBits(0.0f) == 0*/
         if (Float.floatToRawIntBits(f1) != 0) {
             return f2;
         }
@@ -739,8 +762,8 @@
      * <li>{@code round(-0.0) = +0.0}</li>
      * <li>{@code round((anything > Long.MAX_VALUE) = Long.MAX_VALUE}</li>
      * <li>{@code round((anything < Long.MIN_VALUE) = Long.MIN_VALUE}</li>
-     * <li>{@code round(+infintiy) = Long.MAX_VALUE}</li>
-     * <li>{@code round(-infintiy) = Long.MIN_VALUE}</li>
+     * <li>{@code round(+infinity) = Long.MAX_VALUE}</li>
+     * <li>{@code round(-infinity) = Long.MIN_VALUE}</li>
      * <li>{@code round(NaN) = +0.0}</li>
      * </ul>
      * 
@@ -803,7 +826,16 @@
      * @return the value of the signum function.
      */
     public static double signum(double d) {
-        return StrictMath.signum(d);
+        if (Double.isNaN(d)) {
+            return Double.NaN;
+        }
+        double sig = d;
+        if (d > 0) {
+            sig = 1.0;
+        } else if (d < 0) {
+            sig = -1.0;
+        }
+        return sig;
     }
 
     /**
@@ -826,7 +858,16 @@
      * @return the value of the signum function.
      */
     public static float signum(float f) {
-        return StrictMath.signum(f);
+        if (Float.isNaN(f)) {
+            return Float.NaN;
+        }
+        float sig = f;
+        if (f > 0) {
+            sig = 1.0f;
+        } else if (f < 0) {
+            sig = -1.0f;
+        }
+        return sig;
     }
 
     /**
@@ -903,7 +944,7 @@
      * </ul>
      * 
      * @param d
-     *            the angle whose tangens has to be computed, in radians.
+     *            the angle whose tangent has to be computed, in radians.
      * @return the tangent of the argument.
      */
     public static native double tan(double d);
@@ -1050,4 +1091,383 @@
     private native static double nextafter(double x, double y);
 
     private native static float nextafterf(float x, float y);
+    
+    /**
+     * Answers a result of the magnitude of the first given double value and the
+     * sign of the second given double value.
+     * 
+     * @param magnitude
+     *            the double value whose magnitude should be used
+     * @param sign
+     *            the double value whose sign should be used
+     * @return a result of the magnitude of the first given double value and the
+     *         sign of the second given double value .
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static double copySign(double magnitude, double sign) {
+        long mbits = Double.doubleToRawLongBits(magnitude);
+        long sbits = Double.doubleToRawLongBits(sign);
+        return Double.longBitsToDouble((mbits & ~DOUBLE_SIGN_MASK) | (sbits & DOUBLE_SIGN_MASK));
+    }
+
+    /**
+     * Answers a result of the magnitude of the first given float value and the
+     * sign of the second given float value .
+     * 
+     * @param magnitude
+     *            the float value whose magnitude should be used
+     * @param sign
+     *            the float value whose sign should be used
+     * @return a result with the magnitude of the first given float value and
+     *         the sign of the second given float value .
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static float copySign(float magnitude, float sign) {
+        int mbits = Float.floatToRawIntBits(magnitude);
+        int sbits = Float.floatToRawIntBits(sign);
+        return Float.intBitsToFloat((mbits & ~FLOAT_SIGN_MASK) | (sbits & FLOAT_SIGN_MASK));
+    }
+    
+    /**
+     * Answers the exponent of a float.
+     * 
+     * @param f
+     *            the given float
+     * @return the exponent of the float.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static int getExponent(float f) {
+        int bits = Float.floatToRawIntBits(f);
+        bits = (bits & FLOAT_EXPONENT_MASK) >> FLOAT_MANTISSA_BITS;
+        return bits - FLOAT_EXPONENT_BIAS;
+    }
+
+    /**
+     * Answers the exponent of a double.
+     * 
+     * @param d
+     *            the given double
+     * @return the exponent of the double.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static int getExponent(double d) {
+        long bits = Double.doubleToRawLongBits(d);
+        bits = (bits & DOUBLE_EXPONENT_MASK) >> DOUBLE_MANTISSA_BITS;
+        return (int) bits - DOUBLE_EXPONENT_BIAS;
+    }    
+    
+    /**
+     * Answers a double next to the first given double value in the direction of
+     * the second given double.
+     * 
+     * @param start
+     *            the double value to start
+     * @param direction
+     *            the double indicating the direction
+     * @return a double next to the first given double value in the direction of
+     *         the second given double.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static double nextAfter(double start, double direction) {
+        if (start == 0 && direction == 0) {
+            return direction;
+        }
+        return nextafter(start, direction);
+    }
+
+    /**
+     * Answers a float next to the first given float value in the direction of
+     * the second given double value.
+     * 
+     * @param start
+     *            the float value to start
+     * @param direction
+     *            the double indicating the direction
+     * @return a float next to the first given float value in the direction of
+     *         the second given double.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static float nextAfter(float start, double direction) {
+        if (Float.isNaN(start) || Double.isNaN(direction)) {
+            return Float.NaN;
+        }
+        if (start == 0 && direction == 0) {
+            return (float) direction;
+        }
+        if ((start == Float.MIN_VALUE && direction < start)
+                || (start == -Float.MIN_VALUE && direction > start)) {
+            return (start > 0 ? 0f : -0f);
+        }
+        if (Float.isInfinite(start) && (direction != start)) {
+            return (start > 0 ? Float.MAX_VALUE : -Float.MAX_VALUE);
+        }
+        if ((start == Float.MAX_VALUE && direction > start)
+                || (start == -Float.MAX_VALUE && direction < start)) {
+            return (start > 0 ? Float.POSITIVE_INFINITY
+                    : Float.NEGATIVE_INFINITY);
+        }
+        if (direction > start) {
+            if (start > 0) {
+                return Float.intBitsToFloat(Float.floatToIntBits(start) + 1);
+            }
+            if (start < 0) {
+                return Float.intBitsToFloat(Float.floatToIntBits(start) - 1);
+            }
+            return +Float.MIN_VALUE;
+        }
+        if (direction < start) {
+            if (start > 0) {
+                return Float.intBitsToFloat(Float.floatToIntBits(start) - 1);
+            }
+            if (start < 0) {
+                return Float.intBitsToFloat(Float.floatToIntBits(start) + 1);
+            }
+            return -Float.MIN_VALUE;
+        }
+        return (float) direction;
+    }
+    
+    /**
+     * Answers the next larger double value to d.
+     * 
+     * @param d
+     *            the double value to start
+     * @return the next larger double value of d.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static double nextUp(double d) {
+        if (Double.isNaN(d)) {
+            return Double.NaN;
+        }
+        if (d == Double.POSITIVE_INFINITY) {
+            return Double.POSITIVE_INFINITY;
+        }
+        if (d == 0) {
+            return Double.MIN_VALUE;
+        } else if (d > 0) {
+            return Double.longBitsToDouble(Double.doubleToLongBits(d) + 1);
+        } else {
+            return Double.longBitsToDouble(Double.doubleToLongBits(d) - 1);
+        }
+    }
+
+    /**
+     * Answers the next larger float value to d.
+     * 
+     * @param f
+     *            the float value to start
+     * @return the next larger float value of d.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static float nextUp(float f) {
+        if (Float.isNaN(f)) {
+            return Float.NaN;
+        }
+        if (f == Float.POSITIVE_INFINITY) {
+            return Float.POSITIVE_INFINITY;
+        }
+        if (f == 0) {
+            return Float.MIN_VALUE;
+        } else if (f > 0) {
+            return Float.intBitsToFloat(Float.floatToIntBits(f) + 1);
+        } else {
+            return Float.intBitsToFloat(Float.floatToIntBits(f) - 1);
+        }
+    }
+    
+    /**
+     * Answers a double value of d * 2^scaleFactor, the result may be rounded.
+     * 
+     * @param d
+     *            the base number
+     * @param scaleFactor
+     *            the power number
+     * @return d * 2^scaleFactor
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static double scalb(double d, int scaleFactor) {
+        if (Double.isNaN(d) || Double.isInfinite(d) || d == 0) {
+            return d;
+        }
+        // change double to long for calculation
+        long bits = Double.doubleToLongBits(d);
+        // the sign of the results must be the same of given d
+        long sign = bits & DOUBLE_SIGN_MASK;
+        // calculates the factor of the result
+        long factor = ((bits & DOUBLE_EXPONENT_MASK) >> DOUBLE_MANTISSA_BITS)
+                - DOUBLE_EXPONENT_BIAS + scaleFactor;
+
+        // calculates the factor of sub-normal values
+        int subNormalFactor = Long.numberOfLeadingZeros(bits
+                & ~DOUBLE_SIGN_MASK)
+                - DOUBLE_NON_MANTISSA_BITS;
+        if (subNormalFactor < 0) {
+            // not sub-normal values
+            subNormalFactor = 0;
+        } else {
+            factor = factor - subNormalFactor;
+        }
+        if (factor > Double.MAX_EXPONENT) {
+            return (d > 0 ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY);
+        }
+
+        long result;
+        // if result is a sub-normal
+        if (factor <= -DOUBLE_EXPONENT_BIAS) {
+            // the number of digits that shifts
+            long digits = factor + DOUBLE_EXPONENT_BIAS + subNormalFactor;
+            if (Math.abs(d) < Double.MIN_NORMAL) {
+                // origin d is already sub-normal
+                result = shiftLongBits(bits & DOUBLE_MANTISSA_MASK, digits);
+            } else {
+                // origin d is not sub-normal, change mantissa to sub-normal
+                result = shiftLongBits(bits & DOUBLE_MANTISSA_MASK
+                        | 0x0010000000000000L, digits - 1);
+            }
+        } else {
+            if (Math.abs(d) >= Double.MIN_NORMAL) {
+                // common situation
+                result = ((factor + DOUBLE_EXPONENT_BIAS) << DOUBLE_MANTISSA_BITS)
+                        | (bits & DOUBLE_MANTISSA_MASK);
+            } else {
+                // origin d is sub-normal, change mantissa to normal style
+                result = ((factor + DOUBLE_EXPONENT_BIAS) << DOUBLE_MANTISSA_BITS)
+                        | ((bits << (subNormalFactor + 1)) & DOUBLE_MANTISSA_MASK);
+            }
+        }
+        return Double.longBitsToDouble(result | sign);
+    }
+
+    /**
+     * Answers a float value of d * 2^scaleFactor, the result may be rounded.
+     * 
+     * @param d
+     *            the base number
+     * @param scaleFactor
+     *            the power number
+     * @return d * 2^scaleFactor
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static float scalb(float d, int scaleFactor) {
+        if (Float.isNaN(d) || Float.isInfinite(d) || d == 0) {
+            return d;
+        }
+        int bits = Float.floatToIntBits(d);
+        int sign = bits & FLOAT_SIGN_MASK;
+        int factor = ((bits & FLOAT_EXPONENT_MASK) >> FLOAT_MANTISSA_BITS)
+                - FLOAT_EXPONENT_BIAS + scaleFactor;
+        // calcutes the factor of sub-normal values
+        int subNormalFactor = Integer.numberOfLeadingZeros(bits
+                & ~FLOAT_SIGN_MASK)
+                - FLOAT_NON_MANTISSA_BITS;
+        if (subNormalFactor < 0) {
+            // not sub-normal values
+            subNormalFactor = 0;
+        } else {
+            factor = factor - subNormalFactor;
+        }
+        if (factor > Float.MAX_EXPONENT) {
+            return (d > 0 ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY);
+        }
+
+        int result;
+        // if result is a sub-normal
+        if (factor <= -FLOAT_EXPONENT_BIAS) {
+            // the number of digits that shifts
+            int digits = factor + FLOAT_EXPONENT_BIAS + subNormalFactor;
+            if (Math.abs(d) < Float.MIN_NORMAL) {
+                // origin d is already sub-normal
+                result = shiftIntBits(bits & FLOAT_MANTISSA_MASK, digits);
+            } else {
+                // origin d is not sub-normal, change mantissa to sub-normal
+                result = shiftIntBits(bits & FLOAT_MANTISSA_MASK | 0x00800000,
+                        digits - 1);
+            }
+        } else {
+            if (Math.abs(d) >= Float.MIN_NORMAL) {
+                // common situation
+                result = ((factor + FLOAT_EXPONENT_BIAS) << FLOAT_MANTISSA_BITS)
+                        | (bits & FLOAT_MANTISSA_MASK);
+            } else {
+                // origin d is sub-normal, change mantissa to normal style
+                result = ((factor + FLOAT_EXPONENT_BIAS) << FLOAT_MANTISSA_BITS)
+                        | ((bits << (subNormalFactor + 1)) & FLOAT_MANTISSA_MASK);
+            }
+        }
+        return Float.intBitsToFloat(result | sign);
+    }
+
+    // Shifts integer bits as float, if the digits is positive, left-shift; if
+    // not, shift to right and calculate its carry.
+    private static int shiftIntBits(int bits, int digits) {
+        if (digits > 0) {
+            return bits << digits;
+        }
+        // change it to positive
+        int absdigits = -digits;
+        if (!(Integer.numberOfLeadingZeros(bits & ~FLOAT_SIGN_MASK) <= (32 - absdigits))) {
+            return 0;
+        }
+        int ret = bits >> absdigits;
+        boolean halfbit = ((bits >> (absdigits - 1)) & 0x1) == 1;
+        if (halfbit) {
+            if (Integer.numberOfTrailingZeros(bits) < (absdigits - 1)) {
+                ret = ret + 1;
+            }
+            if (Integer.numberOfTrailingZeros(bits) == (absdigits - 1)) {
+                if ((ret & 0x1) == 1) {
+                    ret = ret + 1;
+                }
+            }
+        }
+        return ret;
+    }
+
+    // Shifts long bits as double, if the digits is positive, left-shift; if
+    // not, shift to right and calculate its carry.
+    private static long shiftLongBits(long bits, long digits) {
+        if (digits > 0) {
+            return bits << digits;
+        }
+        // change it to positive
+        long absdigits = -digits;
+        if (!(Long.numberOfLeadingZeros(bits & ~DOUBLE_SIGN_MASK) <= (64 - absdigits))) {
+            return 0;
+        }
+        long ret = bits >> absdigits;
+        boolean halfbit = ((bits >> (absdigits - 1)) & 0x1) == 1;
+        if (halfbit) {
+            // some bits will remain after shifting, calculates its carry
+            // subnormal
+            if (Long.numberOfTrailingZeros(bits) < (absdigits - 1)) {
+                ret = ret + 1;
+            }
+            if (Long.numberOfTrailingZeros(bits) == (absdigits - 1)) {
+                if ((ret & 0x1) == 1) {
+                    ret = ret + 1;
+                }
+            }
+        }
+        return ret;
+    }
 }
diff --git a/libcore/luni/src/main/java/java/lang/StrictMath.java b/libcore/luni/src/main/java/java/lang/StrictMath.java
index b375a0f..5d3ec8f 100644
--- a/libcore/luni/src/main/java/java/lang/StrictMath.java
+++ b/libcore/luni/src/main/java/java/lang/StrictMath.java
@@ -37,6 +37,29 @@
  * <a href="http://www.netlib.org/fdlibm/">http://www.netlib.org/fdlibm/</a>
  */
 public final class StrictMath {
+    private static final int FLOAT_EXPONENT_BIAS = 127;
+
+    private static final int FLOAT_EXPONENT_MASK = 0x7F800000;
+
+    private static final int DOUBLE_EXPONENT_BITS = 12;
+
+    private static final int DOUBLE_MANTISSA_BITS = 52;
+    
+    private static final int FLOAT_EXPONENT_BITS = 9;
+    
+    private static final int FLOAT_MANTISSA_BITS = 23;  
+
+    private static final int DOUBLE_EXPONENT_BIAS = 1023;
+
+    private static final long DOUBLE_EXPONENT_MASK = 0x7ff0000000000000L;
+
+    private static final int FLOAT_MANTISSA_MASK = 0x007fffff;
+
+    private static final int FLOAT_SIGN_MASK = 0x80000000;
+
+    private static final long DOUBLE_MANTISSA_MASK = 0x000fffffffffffffL;
+
+    private static final long DOUBLE_SIGN_MASK = 0x8000000000000000L;
 
     /**
      * The double value closest to e, the base of the natural logarithm.
@@ -73,9 +96,7 @@
      * @return the absolute value of the argument.
      */
     public static double abs(double d) {
-        long bits = Double.doubleToLongBits(d);
-        bits &= 0x7fffffffffffffffL;
-        return Double.longBitsToDouble(bits);
+        return Math.abs(d);
     }
 
     /**
@@ -95,9 +116,7 @@
      *         argument.
      */
     public static float abs(float f) {
-        int bits = Float.floatToIntBits(f);
-        bits &= 0x7fffffff;
-        return Float.intBitsToFloat(bits);
+        return Math.abs(f);
     }
 
     /**
@@ -112,7 +131,7 @@
      *         argument.
      */
     public static int abs(int i) {
-        return i >= 0 ? i : -i;
+        return Math.abs(i);
     }
 
     /**
@@ -127,7 +146,7 @@
      *         argument.
      */
     public static long abs(long l) {
-        return l >= 0 ? l : -l;
+        return Math.abs(l);
     }
 
     /**
@@ -544,7 +563,7 @@
      * @return the larger of {@code i1} and {@code i2}.
      */
     public static int max(int i1, int i2) {
-        return i1 > i2 ? i1 : i2;
+        return Math.max(i1, i2);
     }
 
     /**
@@ -558,7 +577,7 @@
      * @return the larger of {@code l1} and {@code l2}.
      */
     public static long max(long l1, long l2) {
-        return l1 > l2 ? l1 : l2;
+        return Math.max(l1, l2);
     }
 
     /**
@@ -638,7 +657,7 @@
      * @return the smaller of {@code i1} and {@code i2}.
      */
     public static int min(int i1, int i2) {
-        return i1 < i2 ? i1 : i2;
+        return Math.min(i1, i2);
     }
 
     /**
@@ -652,7 +671,7 @@
      * @return the smaller of {@code l1} and {@code l2}.
      */
     public static long min(long l1, long l2) {
-        return l1 < l2 ? l1 : l2;
+        return Math.min(l1, l2);
     }
 
     /**
@@ -702,9 +721,7 @@
      * @return a pseudo-random number.
      */
     public static double random() {
-        if (random == null)
-            random = new Random();
-        return random.nextDouble();
+        return Math.random();
     }
 
     /**
@@ -746,10 +763,7 @@
      * @return the closest integer to the argument.
      */
     public static long round(double d) {
-        // check for NaN
-        if (d != d)
-            return 0L;
-        return (long) Math.floor(d + 0.5d);
+        return Math.round(d);
     }
 
     /**
@@ -772,10 +786,7 @@
      * @return the closest integer to the argument.
      */
     public static int round(float f) {
-        // check for NaN
-        if (f != f)
-            return 0;
-        return (int) Math.floor(f + 0.5f);
+        return Math.round(f);
     }
     
     /**
@@ -798,16 +809,7 @@
      * @return the value of the signum function.
      */
     public static double signum(double d){
-        if(Double.isNaN(d)){
-            return Double.NaN;
-        }
-        double sig = d;
-        if(d > 0){
-            sig = 1.0;
-        }else if (d < 0){
-            sig = -1.0;
-        }
-        return sig;
+        return Math.signum(d);
     }
     
     /**
@@ -830,16 +832,7 @@
      * @return the value of the signum function.
      */
     public static float signum(float f){
-        if(Float.isNaN(f)){
-            return Float.NaN;
-        }
-        float sig = f;
-        if(f > 0){
-            sig = 1.0f;
-        }else if (f < 0){
-            sig = -1.0f;
-        }
-        return sig;
+        return Math.signum(f);
     }
 
     /**
@@ -911,7 +904,7 @@
      * </ul>
      *
      * @param d
-     *            the angle whose tangens has to be computed, in radians.
+     *            the angle whose tangent has to be computed, in radians.
      * @return the tangent of the argument.
      */
     public static native double tan(double d);
@@ -953,7 +946,7 @@
      * @return the degree measure of the angle.
      */
     public static double toDegrees(double angrad) {
-        return angrad * 180d / PI;
+        return Math.toDegrees(angrad);
     }
 
     /**
@@ -974,7 +967,7 @@
      * @return the radian measure of the angle.
      */
     public static double toRadians(double angdeg) {
-        return angdeg / 180d * PI;
+        return Math.toRadians(angdeg);
     }
     
     /**
@@ -987,8 +980,8 @@
      * <ul>
      * <li>{@code ulp(+0.0) = Double.MIN_VALUE}</li>
      * <li>{@code ulp(-0.0) = Double.MIN_VALUE}</li>
-     * <li>{@code ulp(+infintiy) = infinity}</li>
-     * <li>{@code ulp(-infintiy) = infinity}</li>
+     * <li>{@code ulp(+infinity) = infinity}</li>
+     * <li>{@code ulp(-infinity) = infinity}</li>
      * <li>{@code ulp(NaN) = NaN}</li>
      * </ul>
      *
@@ -1017,8 +1010,8 @@
      * <ul>
      * <li>{@code ulp(+0.0) = Float.MIN_VALUE}</li>
      * <li>{@code ulp(-0.0) = Float.MIN_VALUE}</li>
-     * <li>{@code ulp(+infintiy) = infinity}</li>
-     * <li>{@code ulp(-infintiy) = infinity}</li>
+     * <li>{@code ulp(+infinity) = infinity}</li>
+     * <li>{@code ulp(-infinity) = infinity}</li>
      * <li>{@code ulp(NaN) = NaN}</li>
      * </ul>
      *
@@ -1042,4 +1035,301 @@
     private native static double nextafter(double x, double y);
 
     private native static float nextafterf(float x, float y); 
+    
+    /**
+     * Answers a result of the magnitude of the first given double value and the
+     * sign of the second given double value.
+     * 
+     * @param magnitude
+     *            the double value whose magnitude should be used
+     * @param sign
+     *            the double value whose sign should be used
+     * @return a result of the magnitude of the first given double value and the
+     *         sign of the second given double value.
+     *         
+     * @since 1.6
+     * @hide
+     */
+    public static double copySign(double magnitude, double sign) {
+        return Math.copySign(magnitude, sign);
+    }
+
+    /**
+     * Answers a result of the magnitude of the first given float value and the
+     * sign of the second given float value.
+     * 
+     * @param magnitude
+     *            the float value whose magnitude should be used
+     * @param sign
+     *            the float value whose sign should be used
+     * @return a result with the magnitude of the first given float value and
+     *         the sign of the second given float value.
+     *         
+     * @since 1.6
+     * @hide
+     */
+    public static float copySign(float magnitude, float sign) {
+        return Math.copySign(magnitude, sign);
+    }
+    
+    /**
+     * Answers the exponent of a float.
+     * 
+     * @param f
+     *            the given float
+     * @return the exponent of the float.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static int getExponent(float f) {
+        return Math.getExponent(f);
+    }
+    
+    /**
+     * Answers the exponent of a double.
+     * 
+     * @param d
+     *            the given double
+     * @return the exponent of the double.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static int getExponent(double d){
+        return Math.getExponent(d);
+    }
+    
+    /**
+     * Answers a double next to the first given double value in the direction of
+     * the second given double.
+     * 
+     * @param start
+     *            the double value to start
+     * @param direction
+     *            the double indicating the direction
+     * @return a double next to the first given double value in the direction of
+     *         the second given double.
+     *         
+     * @since 1.6
+     * @hide
+     */
+    public static double nextAfter(double start, double direction) {
+        if (start == 0 && direction == 0) {
+            return direction;
+        }
+        return nextafter(start, direction);
+    }
+
+    /**
+     * Answers a float next to the first given float value in the direction of
+     * the second given double value.
+     * 
+     * @param start
+     *            the float value to start
+     * @param direction
+     *            the double indicating the direction
+     * @return a float next to the first given float value in the direction of
+     *         the second given double.
+     *         
+     * @since 1.6
+     * @hide
+     */
+    public static float nextAfter(float start, double direction) {
+        return Math.nextAfter(start, direction);
+    }
+
+    /**
+     * Answers the next larger double value to d.
+     * 
+     * @param d
+     *            the double value to start
+     * @return the next larger double value of d.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static double nextUp(double d) {
+        return Math.nextUp(d);
+    }
+    
+    /**
+     * Answers the next larger float value to d.
+     * 
+     * @param f
+     *            the float value to start
+     * @return the next larger float value of d.
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static float nextUp(float f) {
+        return Math.nextUp(f);
+    }
+    
+    /**
+     * Answers a double value of d 2^scaleFactor, the result may be rounded.
+     * 
+     * @param d
+     *            the base number
+     * @param scaleFactor
+     *            the power number
+     * @return d 2^scaleFactor
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static double scalb(double d, int scaleFactor) {
+        if (Double.isNaN(d) || Double.isInfinite(d) || d == 0) {
+            return d;
+        }
+        // change double to long for calculation
+        long bits = Double.doubleToLongBits(d);
+        // the sign of the results must be the same of given d
+        long sign = bits & DOUBLE_SIGN_MASK;
+        // calculates the factor of the result
+        long factor = (int) ((bits & DOUBLE_EXPONENT_MASK) >> DOUBLE_MANTISSA_BITS)
+                - DOUBLE_EXPONENT_BIAS + scaleFactor;
+
+        // calculates the factor of sub-normal values
+        int subNormalFactor = Long.numberOfLeadingZeros(bits
+                & ~DOUBLE_SIGN_MASK)
+                - DOUBLE_EXPONENT_BITS;
+        if (subNormalFactor < 0) {
+            // not sub-normal values
+            subNormalFactor = 0;
+        }
+        if (Math.abs(d) < Double.MIN_NORMAL) {
+            factor = factor - subNormalFactor;
+        }
+        if (factor > Double.MAX_EXPONENT) {
+            return (d > 0 ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY);
+        }
+
+        long result;
+        // if result is a sub-normal
+        if (factor < -DOUBLE_EXPONENT_BIAS) {
+            // the number of digits that shifts
+            long digits = factor + DOUBLE_EXPONENT_BIAS + subNormalFactor;
+            if (Math.abs(d) < Double.MIN_NORMAL) {
+                // origin d is already sub-normal
+                result = shiftLongBits(bits & DOUBLE_MANTISSA_MASK, digits);
+            } else {
+                // origin d is not sub-normal, change mantissa to sub-normal
+                result = shiftLongBits(bits & DOUBLE_MANTISSA_MASK
+                        | 0x0010000000000000L, digits - 1);
+            }
+        } else {
+            if (Math.abs(d) >= Double.MIN_NORMAL) {
+                // common situation
+                result = ((factor + DOUBLE_EXPONENT_BIAS) << DOUBLE_MANTISSA_BITS)
+                        | (bits & DOUBLE_MANTISSA_MASK);
+            } else {
+                // origin d is sub-normal, change mantissa to normal style
+                result = ((factor + DOUBLE_EXPONENT_BIAS) << DOUBLE_MANTISSA_BITS)
+                        | ((bits << (subNormalFactor + 1)) & DOUBLE_MANTISSA_MASK);
+            }
+        }
+        return Double.longBitsToDouble(result | sign);
+    }
+
+    /**
+     * Answers a float value of d 2^scaleFactor, the result may be rounded.
+     * 
+     * @param d
+     *            the base number
+     * @param scaleFactor
+     *            the power number
+     * @return d 2^scaleFactor
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public static float scalb(float d, int scaleFactor) {
+        if (Float.isNaN(d) || Float.isInfinite(d) || d == 0) {
+            return d;
+        }
+        int bits = Float.floatToIntBits(d);
+        int sign = bits & FLOAT_SIGN_MASK;
+        int factor = ((bits & FLOAT_EXPONENT_MASK) >> FLOAT_MANTISSA_BITS)
+                - FLOAT_EXPONENT_BIAS + scaleFactor;
+        // calculates the factor of sub-normal values
+        int subNormalFactor = Integer.numberOfLeadingZeros(bits
+                & ~FLOAT_SIGN_MASK)
+                - FLOAT_EXPONENT_BITS;
+        if (subNormalFactor < 0) {
+            // not sub-normal values
+            subNormalFactor = 0;
+        }
+        if (Math.abs(d) < Float.MIN_NORMAL) {
+            factor = factor - subNormalFactor;
+        }
+        if (factor > Float.MAX_EXPONENT) {
+            return (d > 0 ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY);
+        }
+
+        int result;
+        // if result is a sub-normal
+        if (factor < -FLOAT_EXPONENT_BIAS) {
+            // the number of digits that shifts
+            int digits = factor + FLOAT_EXPONENT_BIAS + subNormalFactor;
+            if (Math.abs(d) < Float.MIN_NORMAL) {
+                // origin d is already sub-normal
+                result = shiftIntBits(bits & FLOAT_MANTISSA_MASK, digits);
+            } else {
+                // origin d is not sub-normal, change mantissa to sub-normal
+                result = shiftIntBits(bits & FLOAT_MANTISSA_MASK | 0x00800000,
+                        digits - 1);
+            }
+        } else {
+            if (Math.abs(d) >= Float.MIN_NORMAL) {
+                // common situation
+                result = ((factor + FLOAT_EXPONENT_BIAS) << FLOAT_MANTISSA_BITS)
+                        | (bits & FLOAT_MANTISSA_MASK);
+            } else {
+                // origin d is sub-normal, change mantissa to normal style
+                result = ((factor + FLOAT_EXPONENT_BIAS) << FLOAT_MANTISSA_BITS)
+                        | ((bits << (subNormalFactor + 1)) & FLOAT_MANTISSA_MASK);
+            }
+        }
+        return Float.intBitsToFloat(result | sign);
+    }
+
+    // Shifts integer bits as float, if the digits is positive, left-shift; if
+    // not, shift to right and calculate its carry.
+    private static int shiftIntBits(int bits, int digits) {
+        if (digits > 0) {
+            return bits << digits;
+        }
+        // change it to positive
+        int absdigits = -digits;
+        if (Integer.numberOfLeadingZeros(bits & ~FLOAT_SIGN_MASK) <= (32 - absdigits)) {
+            // some bits will remain after shifting, calculates its carry
+            if ((((bits >> (absdigits - 1)) & 0x1) == 0)
+                    || Integer.numberOfTrailingZeros(bits) == (absdigits - 1)) {
+                return bits >> absdigits;
+            }
+            return ((bits >> absdigits) + 1);
+        }
+        return 0;
+    }
+
+    // Shifts long bits as double, if the digits is positive, left-shift; if
+    // not, shift to right and calculate its carry.
+    private static long shiftLongBits(long bits, long digits) {
+        if (digits > 0) {
+            return bits << digits;
+        }
+        // change it to positive
+        long absdigits = -digits;
+        if (Long.numberOfLeadingZeros(bits & ~DOUBLE_SIGN_MASK) <= (64 - absdigits)) {
+            // some bits will remain after shifting, calculates its carry
+            if ((((bits >> (absdigits - 1)) & 0x1) == 0)
+                    || Long.numberOfTrailingZeros(bits) == (absdigits - 1)) {
+                return bits >> absdigits;
+            }
+            return ((bits >> absdigits) + 1);
+        }
+        return 0;
+    }
 }
diff --git a/libcore/luni/src/main/java/java/lang/String.java b/libcore/luni/src/main/java/java/lang/String.java
index eb9b17b..4fe31f2 100644
--- a/libcore/luni/src/main/java/java/lang/String.java
+++ b/libcore/luni/src/main/java/java/lang/String.java
@@ -430,6 +430,84 @@
     }
 
     /**
+     * Converts the byte array to a String using the specified encoding.
+     * 
+     * @param data
+     *            the byte array to convert to a String
+     * @param start
+     *            the starting offset in the byte array
+     * @param length
+     *            the number of bytes to convert
+     * @param encoding
+     *            the encoding
+     * 
+     * @throws IndexOutOfBoundsException
+     *             when <code>length &lt; 0, start &lt; 0</code> or
+     *             <code>start + length &gt; data.length</code>
+     * @throws NullPointerException
+     *             when data is null
+     * 
+     * @see #getBytes()
+     * @see #getBytes(int, int, byte[], int)
+     * @see #getBytes(String)
+     * @see #valueOf(boolean)
+     * @see #valueOf(char)
+     * @see #valueOf(char[])
+     * @see #valueOf(char[], int, int)
+     * @see #valueOf(double)
+     * @see #valueOf(float)
+     * @see #valueOf(int)
+     * @see #valueOf(long)
+     * @see #valueOf(Object)
+     * @since 1.6
+     * @hide
+     */
+    public String(byte[] data, int start, int length, final Charset encoding) {
+        if (encoding == null) {
+            throw new NullPointerException();
+        }
+        if (start < 0 || length < 0 || length > data.length - start) {
+            throw new StringIndexOutOfBoundsException();
+        }
+        CharBuffer cb = encoding.decode(ByteBuffer.wrap(data, start, length));
+        this.lastCharset = encoding;
+        this.offset = 0;
+        this.count = cb.length();
+        this.value = new char[count];
+        System.arraycopy(cb.array(), 0, value, 0, count);
+    }
+
+    /**
+     * Converts the byte array to a String using the specified encoding.
+     * 
+     * @param data
+     *            the byte array to convert to a String
+     * @param encoding
+     *            the encoding
+     * 
+     * @throws NullPointerException
+     *             when data is null
+     * 
+     * @see #getBytes()
+     * @see #getBytes(int, int, byte[], int)
+     * @see #getBytes(String)
+     * @see #valueOf(boolean)
+     * @see #valueOf(char)
+     * @see #valueOf(char[])
+     * @see #valueOf(char[], int, int)
+     * @see #valueOf(double)
+     * @see #valueOf(float)
+     * @see #valueOf(int)
+     * @see #valueOf(long)
+     * @see #valueOf(Object)
+     * @since 1.6
+     * @hide
+     */
+    public String(byte[] data, Charset encoding) {
+        this(data, 0, data.length, encoding);
+    }
+    
+    /**
      * Initializes this string to contain the characters in the specified
      * character array. Modifying the character array after creating the string
      * has no effect on the string.
@@ -900,11 +978,7 @@
      * @return the byte array encoding of this string.
      */
     public byte[] getBytes() {
-        ByteBuffer buffer = defaultCharset().encode(
-                CharBuffer.wrap(this.value, this.offset, this.count));
-        byte[] bytes = new byte[buffer.limit()];
-        buffer.get(bytes);
-        return bytes;
+        return getBytes(defaultCharset());
     }
 
     /**
@@ -952,11 +1026,7 @@
      *             if the encoding is not supported.
      */
     public byte[] getBytes(String encoding) throws UnsupportedEncodingException {
-        ByteBuffer buffer = getCharset(encoding).encode(
-                CharBuffer.wrap(this.value, this.offset, this.count));
-        byte[] bytes = new byte[buffer.limit()];
-        buffer.get(bytes);
-        return bytes;
+        return getBytes(getCharset(encoding));
     }
 
     private Charset getCharset(final String encoding)
@@ -978,6 +1048,23 @@
     }
 
     /**
+     * Returns a new byte array containing the characters of this string encoded in the
+     * given charset.
+     * 
+     * @param encoding the encoding
+     * 
+     * @since 1.6
+     * @hide
+     */
+    public byte[] getBytes(Charset encoding) {
+        CharBuffer chars = CharBuffer.wrap(this.value, this.offset, this.count);
+        ByteBuffer buffer = encoding.encode(chars.asReadOnlyBuffer());
+        byte[] bytes = new byte[buffer.limit()];
+        buffer.get(bytes);
+        return bytes;
+    }
+
+    /**
      * Copies the specified characters in this string to the character array
      * starting at the specified offset in the character array.
      * 
@@ -2202,8 +2289,16 @@
     }
 
     /**
-     * Returns a formatted string, using the supplied format and arguments,
-     * using the default locale.
+     * Returns a localized formatted string, using the supplied format and arguments,
+     * using the user's default locale.
+     * 
+     * <p>Note that this method can be dangerous: the user's default locale may
+     * not be the locale you tested in, and this may have unexpected effects on
+     * the output. In particular, floating point numbers may be output with
+     * ',' instead of '.' as the decimal separator if that's what the user's
+     * locale dictates. If you're formatting a string other than for human
+     * consumption, you should use the {@code format(Locale, String, Object...)}
+     * overload and supply {@code Locale.US}.
      * 
      * @param format
      *            a format string.
@@ -2223,7 +2318,7 @@
 
     /**
      * Returns a formatted string, using the supplied format and arguments,
-     * accordingly to the specified locale.
+     * localized to the given locale.
      * <p>
      * Note that this is a convenience method. Using it involves creating an
      * internal {@link java.util.Formatter} instance on-the-fly, which is
diff --git a/libcore/luni/src/main/java/java/lang/StringBuffer.java b/libcore/luni/src/main/java/java/lang/StringBuffer.java
index 3ec43dc..766b942 100644
--- a/libcore/luni/src/main/java/java/lang/StringBuffer.java
+++ b/libcore/luni/src/main/java/java/lang/StringBuffer.java
@@ -24,21 +24,22 @@
 import java.io.Serializable;
 
 /**
- * StringBuffer is a variable size contiguous indexable array of characters. The
- * length of the StringBuffer is the number of characters it contains. The
- * capacity of the StringBuffer is the number of characters it can hold.
- * <p>
- * Characters may be inserted at any position up to the length of the
- * StringBuffer, increasing the length of the StringBuffer. Characters at any
- * position in the StringBuffer may be replaced, which does not affect the
- * StringBuffer length.
- * <p>
- * The capacity of a StringBuffer may be specified when the StringBuffer is
- * created. If the capacity of the StringBuffer is exceeded, the capacity is
- * increased.
+ * A modifiable {@link CharSequence sequence of characters} for use in creating
+ * strings, where all accesses are synchronized. This class has mostly been replaced
+ * by {@link StringBuilder} because this synchronization is rarely useful. This
+ * class is mainly used to interact with legacy APIs that expose it.
  * 
- * @see String
+ * <p>For particularly complex string-building needs, consider {@link java.util.Formatter}.
+ * 
+ * <p>The majority of the modification methods on this class return {@code
+ * this} so that method calls can be chained together. For example:
+ * {@code new StringBuffer("a").append("b").append("c").toString()}.
+ * 
+ * @see CharSequence
+ * @see Appendable
  * @see StringBuilder
+ * @see String
+ * @see String.format
  * @since 1.0
  */
 public final class StringBuffer extends AbstractStringBuilder implements
diff --git a/libcore/luni/src/main/java/java/lang/StringBuilder.java b/libcore/luni/src/main/java/java/lang/StringBuilder.java
index 12d401f..775864e 100644
--- a/libcore/luni/src/main/java/java/lang/StringBuilder.java
+++ b/libcore/luni/src/main/java/java/lang/StringBuilder.java
@@ -24,20 +24,21 @@
 
 /**
  * A modifiable {@link CharSequence sequence of characters} for use in creating
- * and modifying Strings. This class is intended as a direct replacement of
+ * strings. This class is intended as a direct replacement of
  * {@link StringBuffer} for non-concurrent use; unlike {@code StringBuffer} this
- * class is not synchronized for thread safety.
- * <p>
- * The majority of the modification methods on this class return {@code
- * StringBuilder}, so that, like {@code StringBuffer}s, they can be used in
- * chaining method calls together. For example, {@code new StringBuilder("One
- * should ").append("always strive ").append("to achieve Harmony")}.
+ * class is not synchronized.
+ * 
+ * <p>For particularly complex string-building needs, consider {@link java.util.Formatter}.
+ * 
+ * <p>The majority of the modification methods on this class return {@code
+ * this} so that method calls can be chained together. For example:
+ * {@code new StringBuilder("a").append("b").append("c").toString()}.
  * 
  * @see CharSequence
  * @see Appendable
  * @see StringBuffer
  * @see String
- * 
+ * @see String.format
  * @since 1.5
  */
 public final class StringBuilder extends AbstractStringBuilder implements
diff --git a/libcore/luni/src/main/java/java/net/ServerSocket.java b/libcore/luni/src/main/java/java/net/ServerSocket.java
index 2fe6b5c..ce7b84f 100644
--- a/libcore/luni/src/main/java/java/net/ServerSocket.java
+++ b/libcore/luni/src/main/java/java/net/ServerSocket.java
@@ -61,13 +61,7 @@
     }
 
     /**
-     * Unspecified constructor.
-     *
-     * Warning: this function is technically part of API#1.
-     * Hiding it for API#2 broke source compatibility.
-     * Removing it entirely would theoretically break binary compatibility,
-     *     and would be better done with some visibility over the extent
-     *     of the compatibility breakage (expected to be non-existent).
+     * Unspecified constructor needed by ServerSocketChannelImpl.ServerSocketAdapter.
      *
      * @hide
      */
diff --git a/libcore/luni/src/main/java/java/util/ArrayList.java b/libcore/luni/src/main/java/java/util/ArrayList.java
index 7c46e89..ba96593 100644
--- a/libcore/luni/src/main/java/java/util/ArrayList.java
+++ b/libcore/luni/src/main/java/java/util/ArrayList.java
@@ -29,10 +29,18 @@
 import java.lang.reflect.Array;
 
 /**
- * ArrayList is an implementation of {@link List}, backed by an array. All
- * optional operations adding, removing, and replacing are supported. The
- * elements can be any objects.
- *
+ * ArrayList is an implementation of {@link List}, backed by an array.
+ * All optional operations including adding, removing, and replacing elements are supported.
+ * 
+ * <p>All elements are permitted, including null.
+ * 
+ * <p>This class is a good choice as your default {@code List} implementation.
+ * {@link Vector} synchronizes all operations, but not necessarily in a way that's
+ * meaningful to your application: synchronizing each call to {@code get}, for example, is not
+ * equivalent to synchronizing the list and iterating over it (which is probably what you intended).
+ * {@link java.util.concurrent.CopyOnWriteArrayList} is intended for the special case of very high
+ * concurrency, frequent traversals, and very rare mutations.
+ * 
  * @param <E> The element type of this list.
  * @since 1.2
  */
diff --git a/libcore/luni/src/main/java/java/util/Enumeration.java b/libcore/luni/src/main/java/java/util/Enumeration.java
index 8b8f7bd..5944a75 100644
--- a/libcore/luni/src/main/java/java/util/Enumeration.java
+++ b/libcore/luni/src/main/java/java/util/Enumeration.java
@@ -18,15 +18,19 @@
 package java.util;
 
 /**
- * An Enumeration is used to sequence over a collection of objects.
- * <p>
- * Preferably an {@link Iterator} should be used. {@code Iterator} replaces the
+ * A legacy iteration interface.
+ * 
+ * <p>New code should use {@link Iterator} instead. {@code Iterator} replaces the
  * enumeration interface and adds a way to remove elements from a collection.
- *
- * @see Hashtable
- * @see Properties
- * @see Vector
+ * 
+ * <p>If you <i>have</i> an {@code Enumeration} and want a {@code Collection}, you
+ * can use {@link Collections#list} to get a {@code List}.
+ * 
+ * <p>If you <i>need</i> an {@code Enumeration} for a legacy API and have a
+ * {@code Collection}, you can use {@link Collections#enumeration}.
+ * 
  * @version 1.0
+ * @see Iterator
  */
 public interface Enumeration<E> {
 
diff --git a/libcore/luni/src/main/java/java/util/Formatter.java b/libcore/luni/src/main/java/java/util/Formatter.java
index 09ea5fc..d2e59e6 100644
--- a/libcore/luni/src/main/java/java/util/Formatter.java
+++ b/libcore/luni/src/main/java/java/util/Formatter.java
@@ -1347,7 +1347,7 @@
                 break;
 
             default:
-                throw new AssertionError(conversionType);
+                throw new UnknownFormatConversionException(String.valueOf(conversionType));
             }
             
             // Check for disallowed flags.
diff --git a/libcore/luni/src/main/java/java/util/HashMap.java b/libcore/luni/src/main/java/java/util/HashMap.java
index f79601f..19aa2b8 100644
--- a/libcore/luni/src/main/java/java/util/HashMap.java
+++ b/libcore/luni/src/main/java/java/util/HashMap.java
@@ -29,14 +29,31 @@
 import java.io.Serializable;
 
 /**
- * HashMap is an implementation of Map. All optional operations (adding and
- * removing) are supported. Keys and values can be any objects.
- *
+ * HashMap is an implementation of {@link Map}. All optional operations are supported.
+ * 
+ * <p>All elements are permitted as keys or values, including null.
+ * 
+ * <p>Note that the iteration order for HashMap is non-deterministic. If you want
+ * deterministic iteration, use {@link LinkedHashMap}.
+ * 
+ * <p>Note: the implementation of {@code HashMap} is not synchronized.
+ * If one thread of several threads accessing an instance modifies the map
+ * structurally, access to the map needs to be synchronized. A structural
+ * modification is an operation that adds or removes an entry. Changes in
+ * the value of an entry are not structural changes.
+ * 
+ * <p>The {@code Iterator} created by calling the {@code iterator} method
+ * may throw a {@code ConcurrentModificationException} if the map is structurally
+ * changed while an iterator is used to iterate over the elements. Only the
+ * {@code remove} method that is provided by the iterator allows for removal of
+ * elements during iteration. It is not possible to guarantee that this
+ * mechanism works in all cases of unsynchronized concurrent modification. It
+ * should only be used for debugging purposes.
+ * 
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
  */
-public class HashMap<K, V> extends AbstractMap<K, V>
-        implements Cloneable, Serializable {
+public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable {
     /**
      * Min capacity (other than zero) for a HashMap. Must be a power of two
      * greater than 1 (and less than 1 << 30).
@@ -60,7 +77,7 @@
     /**
      * The default load factor. Note that this implementation ignores the
      * load factor, but cannot do away with it entirely because it's
-     * metioned in the API.
+     * mentioned in the API.
      *
      * <p>Note that this constant has no impact on the behavior of the program,
      * but it is emitted as part of the serialized form. The load factor of
@@ -165,7 +182,7 @@
 
         /*
          * Note that this implementation ignores loadFactor; it always uses
-         * a load facator of 3/4. This simplifies the code and generally
+         * a load factor of 3/4. This simplifies the code and generally
          * improves performance.
          */
     }
@@ -184,7 +201,7 @@
 
     /**
      * Inserts all of the elements of map into this HashMap in a manner
-     * suitable for use by constructors and pseudocostructors (i.e., clone,
+     * suitable for use by constructors and pseudo-constructors (i.e., clone,
      * readObject). Also used by LinkedHashMap.
      */
     final void constructorPutAll(Map<? extends K, ? extends V> map) {
@@ -239,7 +256,7 @@
     /**
      * This method is called from the pseudo-constructors (clone and readObject)
      * prior to invoking constructorPut/constructorPutAll, which invoke the
-     * overriden constructorNewEntry method. Normally it is a VERY bad idea to
+     * overridden constructorNewEntry method. Normally it is a VERY bad idea to
      * invoke an overridden method from a pseudo-constructor (Effective Java
      * Item 17). In this cases it is unavoidable, and the init method provides a
      * workaround.
@@ -411,7 +428,7 @@
     }
 
     /**
-     * Give LinkedHashMap a chance to take action when we modify an exisitng
+     * Give LinkedHashMap a chance to take action when we modify an existing
      * entry.
      *
      * @param e the entry we're about to modify.
@@ -879,7 +896,7 @@
         return o1 == o2 || (o1 != null && o1.equals(o2));
     }
 
-    // Subclass (LinkedHashMap) overrrides these for correct iteration order
+    // Subclass (LinkedHashMap) overrides these for correct iteration order
     Iterator<K> newKeyIterator() { return new KeyIterator();   }
     Iterator<V> newValueIterator() { return new ValueIterator(); }
     Iterator<Entry<K, V>> newEntryIterator() { return new EntryIterator(); }
diff --git a/libcore/luni/src/main/java/java/util/Hashtable.java b/libcore/luni/src/main/java/java/util/Hashtable.java
index ead0db3..af0f4b3 100644
--- a/libcore/luni/src/main/java/java/util/Hashtable.java
+++ b/libcore/luni/src/main/java/java/util/Hashtable.java
@@ -29,22 +29,15 @@
 import java.io.Serializable;
 
 /**
- * Hashtable associates keys with values. Both keys and values cannot be null.
- * The size of the Hashtable is the number of key/value pairs it contains. The
- * capacity is the number of key/value pairs the Hashtable can hold. The load
- * factor is a float value which determines how full the Hashtable gets before
- * expanding the capacity. If the load factor of the Hashtable is exceeded, the
- * capacity is doubled.
- *
+ * Hashtable is a synchronized implementation of {@link Map}. All optional operations are supported.
+ * 
+ * <p>Neither keys nor values can be null. (Use {@code HashMap} or {@code LinkedHashMap} if you
+ * need null keys or values.)
+ * 
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
- *
- * @see Enumeration
- * @see java.io.Serializable
- * @see java.lang.Object#equals
- * @see java.lang.Object#hashCode
+ * @see HashMap
  */
-
 public class Hashtable<K, V> extends Dictionary<K, V>
         implements Map<K, V>, Cloneable, Serializable {
     /**
@@ -70,7 +63,7 @@
     /**
      * The default load factor. Note that this implementation ignores the
      * load factor, but cannot do away with it entirely because it's
-     * metioned in the API.
+     * mentioned in the API.
      *
      * <p>Note that this constant has no impact on the behavior of the program,
      * but it is emitted as part of the serialized form. The load factor of
@@ -166,7 +159,7 @@
 
         /*
          * Note that this implementation ignores loadFactor; it always uses
-         * a load facator of 3/4. This simplifies the code and generally
+         * a load factor of 3/4. This simplifies the code and generally
          * improves performance.
          */
     }
@@ -185,7 +178,7 @@
 
     /**
      * Inserts all of the elements of map into this Hashtable in a manner
-     * suitable for use by constructors and pseudocostructors (i.e., clone,
+     * suitable for use by constructors and pseudo-constructors (i.e., clone,
      * readObject).
      */
     private void constructorPutAll(Map<? extends K, ? extends V> map) {
@@ -665,7 +658,7 @@
     /**
      * Note: technically the methods of this class should synchronize the
      * backing map.  However, this would require them to have a reference
-     * to it, which would cause consiserable bloat.  Moreover, the RI
+     * to it, which would cause considerable bloat.  Moreover, the RI
      * behaves the same way.
      */
     private static class HashtableEntry<K, V> implements Entry<K, V> {
diff --git a/libcore/luni/src/main/java/java/util/Iterator.java b/libcore/luni/src/main/java/java/util/Iterator.java
index 6ebae04..bec797b 100644
--- a/libcore/luni/src/main/java/java/util/Iterator.java
+++ b/libcore/luni/src/main/java/java/util/Iterator.java
@@ -18,31 +18,29 @@
 package java.util;
 
 /**
- * An {@code Iterator} is used to sequence over a collection of objects.
- * Conceptually, an iterator is always positioned between two elements of a
- * collection. A fresh iterator is always positioned in front of the first
- * element.
+ * An iterator over a sequence of objects, such as a collection.
  * 
- * If a collection has been changed since its creation, methods {@code next} and
- * {@code hasNext()} may throw a {@code ConcurrentModificationException}.
- * Iterators with this behavior are called fail-fast iterators.
+ * <p>If a collection has been changed since the iterator was created,
+ * methods {@code next} and {@code hasNext()} may throw a {@code ConcurrentModificationException}.
+ * It is not possible to guarantee that this mechanism works in all cases of unsynchronized
+ * concurrent modification. It should only be used for debugging purposes. Iterators with this
+ * behavior are called fail-fast iterators.
+ * 
+ * <p>Implementing {@link Iterable} and returning an {@code Iterator} allows your
+ * class to be used as a collection with the enhanced for loop.
  * 
  * @param <E>
  *            the type of object returned by the iterator.
  */
 public interface Iterator<E> {
     /**
-     * Returns whether there are more elements to iterate, i.e. whether the
-     * iterator is positioned in front of an element.
-     * 
-     * @return {@code true} if there are more elements, {@code false} otherwise.
+     * Returns true if there is at least one more element, false otherwise.
      * @see #next
      */
     public boolean hasNext();
 
     /**
-     * Returns the next object in the iteration, i.e. returns the element in
-     * front of the iterator and advances the iterator by one position.
+     * Returns the next object and advances the iterator.
      * 
      * @return the next object.
      * @throws NoSuchElementException
@@ -53,7 +51,7 @@
 
     /**
      * Removes the last object returned by {@code next} from the collection.
-     * This method can only be called once after {@code next} was called.
+     * This method can only be called once between each call to {@code next}.
      * 
      * @throws UnsupportedOperationException
      *             if removing is not supported by the collection being
diff --git a/libcore/luni/src/main/java/java/util/LinkedHashMap.java b/libcore/luni/src/main/java/java/util/LinkedHashMap.java
index cd6825b..eeee1a9 100644
--- a/libcore/luni/src/main/java/java/util/LinkedHashMap.java
+++ b/libcore/luni/src/main/java/java/util/LinkedHashMap.java
@@ -22,28 +22,28 @@
 package java.util;
 
 /**
- * LinkedHashMap is a variant of HashMap. Its entries are kept in a
- * doubly-linked list. The iteration order is, by default, the order in which
- * keys were inserted. Reinserting an already existing key doesn't change the
- * order. A key is existing if a call to {@code containsKey} would return true.
- * <p>
- * If the three argument constructor is used, and {@code order} is specified as
+ * LinkedHashMap is an implementation of {@link Map} that guarantees iteration order.
+ * All optional operations are supported.
+ * 
+ * <p>All elements are permitted as keys or values, including null.
+ * 
+ * <p>Entries are kept in a doubly-linked list. The iteration order is, by default, the
+ * order in which keys were inserted. Reinserting an already-present key doesn't change the
+ * order. If the three argument constructor is used, and {@code accessOrder} is specified as
  * {@code true}, the iteration will be in the order that entries were accessed.
- * The access order gets affected by put(), get(), putAll() operations, but not
- * by operations on the collection views.
- * <p>
- * Null elements are allowed, and all the optional map operations are supported.
- * <p>
- * <b>Note:</b> The implementation of {@code LinkedHashMap} is not synchronized.
+ * The access order is affected by {@code put}, {@code get}, and {@code putAll} operations,
+ * but not by operations on the collection views.
+ * 
+ * <p>Note: the implementation of {@code LinkedHashMap} is not synchronized.
  * If one thread of several threads accessing an instance modifies the map
  * structurally, access to the map needs to be synchronized. For
  * insertion-ordered instances a structural modification is an operation that
  * removes or adds an entry. Access-ordered instances also are structurally
- * modified by put(), get() and putAll() since these methods change the order of
- * the entries. Changes in the value of an entry are not structural changes.
- * <p>
- * The Iterator that can be created by calling the {@code iterator} method
- * throws a {@code ConcurrentModificationException} if the map is structurally
+ * modified by {@code put}, {@code get}, and {@code putAll} since these methods
+ * change the order of the entries. Changes in the value of an entry are not structural changes.
+ * 
+ * <p>The {@code Iterator} created by calling the {@code iterator} method
+ * may throw a {@code ConcurrentModificationException} if the map is structurally
  * changed while an iterator is used to iterate over the elements. Only the
  * {@code remove} method that is provided by the iterator allows for removal of
  * elements during iteration. It is not possible to guarantee that this
diff --git a/libcore/luni/src/main/java/java/util/LinkedList.java b/libcore/luni/src/main/java/java/util/LinkedList.java
index 7a7e81f..9db9c9c 100644
--- a/libcore/luni/src/main/java/java/util/LinkedList.java
+++ b/libcore/luni/src/main/java/java/util/LinkedList.java
@@ -24,10 +24,16 @@
 import java.lang.reflect.Array;
 
 /**
- * LinkedList is an implementation of List, backed by a linked list. All
- * optional operations (adding, removing and replacing) are supported. The
- * elements can be any objects.
- *
+ * LinkedList is an implementation of {@link List}, backed by a doubly-linked list.
+ * All optional operations including adding, removing, and replacing elements are supported.
+ * 
+ * <p>All elements are permitted, including null.
+ * 
+ * <p>This class is primarily useful if you need queue-like behavior. It may also be useful
+ * as a list if you expect your lists to contain zero or one element, but still require the
+ * ability to scale to slightly larger numbers of elements. In general, though, you should
+ * probably use {@link ArrayList} if you don't need the queue-like behavior.
+ * 
  * @since 1.2
  */
 public class LinkedList<E> extends AbstractSequentialList<E> implements
diff --git a/libcore/luni/src/main/java/java/util/Vector.java b/libcore/luni/src/main/java/java/util/Vector.java
index 9a1b81c..3e862ce 100644
--- a/libcore/luni/src/main/java/java/util/Vector.java
+++ b/libcore/luni/src/main/java/java/util/Vector.java
@@ -23,20 +23,18 @@
 import java.lang.reflect.Array;
 
 /**
- * Vector is a variable size contiguous indexable array of objects. The size of
- * the vector is the number of objects it contains. The capacity of the vector
- * is the number of objects it can hold.
- * <p>
- * Objects may be inserted at any position up to the size of the vector, thus
- * increasing the size of the vector. Objects at any position in the vector may
- * be removed, thus shrinking the size of the Vector. Objects at any position in
- * the Vector may be replaced, which does not affect the vector's size.
- * <p>
- * The capacity of a vector may be specified when the vector is created. If the
- * capacity of the vector is exceeded, the capacity is increased (doubled by
- * default).
- *
- * @see java.lang.StringBuffer
+ * Vector is an implementation of {@link List}, backed by an array and synchronized.
+ * All optional operations including adding, removing, and replacing elements are supported.
+ * 
+ * <p>All elements are permitted, including null.
+ * 
+ * <p>This class is equivalent to {@link ArrayList} with synchronized operations. This has a
+ * performance cost, and the synchronization is not necessarily meaningful to your application:
+ * synchronizing each call to {@code get}, for example, is not equivalent to synchronizing on the
+ * list and iterating over it (which is probably what you intended). If you do need very highly
+ * concurrent access, you should also consider {@link java.util.concurrent.CopyOnWriteArrayList}.
+ * 
+ * @param <E> The element type of this list.
  */
 public class Vector<E> extends AbstractList<E> implements List<E>,
         RandomAccess, Cloneable, Serializable {
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/jar/JarURLConnectionImpl.java b/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/jar/JarURLConnectionImpl.java
index 493b768..eb678f8 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/jar/JarURLConnectionImpl.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/jar/JarURLConnectionImpl.java
@@ -150,24 +150,32 @@
                 jar = AccessController
                         .doPrivileged(new PrivilegedAction<JarFile>() {
                             public JarFile run() {
+                                FileOutputStream fos = null;
+                                JarFile result = null;
                                 try {
-                                    File tempJar = File.createTempFile(
-                                            "hyjar_", ".tmp", null);
+                                    File tempJar = File.createTempFile("hyjar_", ".tmp", null);
                                     tempJar.deleteOnExit();
-                                    FileOutputStream fos = new FileOutputStream(
-                                            tempJar);
+                                    fos = new FileOutputStream(tempJar);
                                     byte[] buf = new byte[4096];
                                     int nbytes = 0;
                                     while ((nbytes = is.read(buf)) > -1) {
                                         fos.write(buf, 0, nbytes);
                                     }
                                     fos.close();
-                                    return new JarFile(tempJar, true,
-                                            ZipFile.OPEN_READ
-                                                    | ZipFile.OPEN_DELETE);
+                                    result = new JarFile(tempJar, true,
+                                            ZipFile.OPEN_READ | ZipFile.OPEN_DELETE);
                                 } catch (IOException e) {
                                     return null;
+                                } finally {
+                                    if (fos != null) {
+                                        try {
+                                            fos.close();
+                                        } catch (IOException ex) {
+                                            result = null;
+                                        }
+                                    }
                                 }
+                                return result;
                             }
                         });
             } finally {
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/net/PlainDatagramSocketImpl.java b/libcore/luni/src/main/java/org/apache/harmony/luni/net/PlainDatagramSocketImpl.java
index 4d75faf..e2ea82c 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/net/PlainDatagramSocketImpl.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/net/PlainDatagramSocketImpl.java
@@ -75,8 +75,6 @@
 
     private byte[] ipaddress = { 0, 0, 0, 0 };
 
-    private int ttl = 1;
-
     private INetworkSystem netImpl = Platform.getNetworkSystem();
 
     private volatile boolean isNativeConnected;
@@ -160,41 +158,18 @@
         } else if (optID == SocketOptions.IP_TOS) {
             return Integer.valueOf(trafficClass);
         } else {
-            // Call the native first so there will be
-            // an exception if the socket if closed.
-            Object result = netImpl.getSocketOption(fd, optID);
-            if (optID == SocketOptions.IP_MULTICAST_IF
-                    && (netImpl.getSocketFlags() & MULTICAST_IF) != 0) {
-                try {
-                    return InetAddress.getByAddress(ipaddress);
-                } catch (UnknownHostException e) {
-                    return null;
-                }
-            }
-            return result;
+            return netImpl.getSocketOption(fd, optID);
         }
     }
 
     @Override
     public int getTimeToLive() throws IOException {
-        // Call the native first so there will be an exception if the socket if
-        // closed.
-        int result = (((Byte) getOption(IP_MULTICAST_TTL)).byteValue()) & 0xFF;
-        if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
-            return ttl;
-        }
-        return result;
+        return getTTL() & 0xff;
     }
 
     @Override
     public byte getTTL() throws IOException {
-        // Call the native first so there will be an exception if the socket if
-        // closed.
-        byte result = ((Byte) getOption(IP_MULTICAST_TTL)).byteValue();
-        if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
-            return (byte) ttl;
-        }
-        return result;
+        return ((Byte) getOption(IP_MULTICAST_TTL)).byteValue();
     }
 
     @Override
@@ -293,13 +268,11 @@
         if (optID == SocketOptions.SO_REUSEADDR) {
             optID = REUSEADDR_AND_REUSEPORT;
         }
-
         if (optID == SocketOptions.SO_TIMEOUT) {
             receiveTimeout = ((Integer) val).intValue();
         } else {
-            int flags = netImpl.getSocketFlags();
             try {
-                netImpl.setSocketOption(fd, optID | (flags << 16), val);
+                netImpl.setSocketOption(fd, optID, val);
             } catch (SocketException e) {
                 // we don't throw an exception for IP_TOS even if the platform
                 // won't let us set the requested value
@@ -307,24 +280,6 @@
                     throw e;
                 }
             }
-            if (optID == SocketOptions.IP_MULTICAST_IF && (flags & MULTICAST_IF) != 0) {
-                InetAddress inet = (InetAddress) val;
-                if (NetUtil.bytesToInt(inet.getAddress(), 0) == 0 || inet.isLoopbackAddress()) {
-                    ipaddress = ((InetAddress) val).getAddress();
-                } else {
-                    InetAddress local = null;
-                    try {
-                        local = InetAddress.getLocalHost();
-                    } catch (UnknownHostException e) {
-                        throw new SocketException("getLocalHost(): " + e.toString());
-                    }
-                    if (inet.equals(local)) {
-                        ipaddress = ((InetAddress) val).getAddress();
-                    } else {
-                        throw new SocketException(val + " != getLocalHost(): " + local);
-                    }
-                }
-            }
             /*
              * save this value as it is actually used differently for IPv4 and
              * IPv6 so we cannot get the value using the getOption. The option
@@ -341,20 +296,13 @@
     }
 
     @Override
-    public void setTimeToLive(int ttl) throws java.io.IOException {
-        // BEGIN android-changed: native code wants an int anyway
+    public void setTimeToLive(int ttl) throws IOException {
         setOption(IP_MULTICAST_TTL, Integer.valueOf(ttl));
-        // END android-changed
-        if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
-            this.ttl = ttl;
-        }
     }
 
     @Override
-    public void setTTL(byte ttl) throws java.io.IOException {
-        // BEGIN android-changed: remove duplication
+    public void setTTL(byte ttl) throws IOException {
         setTimeToLive(ttl);
-        // END android-changed
     }
 
     @Override
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/net/PlainSocketImpl.java b/libcore/luni/src/main/java/org/apache/harmony/luni/net/PlainSocketImpl.java
index 09b61da..e6268c2 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/net/PlainSocketImpl.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/net/PlainSocketImpl.java
@@ -45,16 +45,6 @@
  */
 public class PlainSocketImpl extends SocketImpl {
 
-    // Const copy from socket
-
-    static final int MULTICAST_IF = 1;
-
-    static final int MULTICAST_TTL = 2;
-
-    static final int TCP_NODELAY = 4;
-
-    static final int FLAG_SHUTDOWN = 8;
-
     // For SOCKS support. A SOCKS bind() uses the last
     // host connected to in its request.
     static private InetAddress lastConnectedAddress;
@@ -65,8 +55,6 @@
 
     private static Field localportField;
 
-    private boolean tcpNoDelay = true;
-
     /**
      * used to store the trafficClass value which is simply returned as the
      * value that was set. We also need it to pass it to methods that specify an
@@ -176,7 +164,7 @@
         if (shutdownInput == true) {
             return 0;
         }
-        return netImpl.availableStream(fd);
+        return Platform.getFileSystem().ioctlAvailable(fd);
     }
 
     @Override
@@ -195,12 +183,6 @@
     protected void close() throws IOException {
         synchronized (fd) {
             if (fd.valid()) {
-                if ((netImpl.getSocketFlags() & FLAG_SHUTDOWN) != 0) {
-                    try {
-                        shutdownOutput();
-                    } catch (Exception e) {
-                    }
-                }
                 netImpl.socketClose(fd);
                 fd = new FileDescriptor();
             }
@@ -289,14 +271,7 @@
         } else if (optID == SocketOptions.IP_TOS) {
             return Integer.valueOf(trafficClass);
         } else {
-            // Call the native first so there will be
-            // an exception if the socket if closed.
-            Object result = netImpl.getSocketOption(fd, optID);
-            if (optID == SocketOptions.TCP_NODELAY
-                    && (netImpl.getSocketFlags() & TCP_NODELAY) != 0) {
-                return Boolean.valueOf(tcpNoDelay);
-            }
-            return result;
+            return netImpl.getSocketOption(fd, optID);
         }
     }
 
@@ -325,10 +300,6 @@
         } else {
             try {
                 netImpl.setSocketOption(fd, optID, val);
-                if (optID == SocketOptions.TCP_NODELAY
-                        && (netImpl.getSocketFlags() & TCP_NODELAY) != 0) {
-                    tcpNoDelay = ((Boolean) val).booleanValue();
-                }
             } catch (SocketException e) {
                 // we don't throw an exception for IP_TOS even if the platform
                 // won't let us set the requested value
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java
index bee1557..f04ea02 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/IFileSystem.java
@@ -112,7 +112,7 @@
     // END android-deleted
     
     // BEGIN android-added
-    public int ioctlAvailable(int fileDescriptor) throws IOException;
+    public int ioctlAvailable(FileDescriptor fileDescriptor) throws IOException;
     // END android-added
     
 }
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
index bc56f68..7ffb30c 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/INetworkSystem.java
@@ -142,8 +142,6 @@
 
     public void sendUrgentData(FileDescriptor fd, byte value);
 
-    public int availableStream(FileDescriptor aFD) throws SocketException;
-
     // BEGIN android-removed
     // public void acceptStreamSocket(FileDescriptor fdServer,
     //         SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout)
@@ -236,8 +234,6 @@
     public void setSocketOption(FileDescriptor aFD, int opt, Object optVal)
             throws SocketException;
 
-    public int getSocketFlags();
-
     /*
      * Close the socket in the IP stack.
      * 
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java
index 13ca3ab..1f8eb4a 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSFileSystem.java
@@ -182,6 +182,6 @@
     // END android-deleted
 
     // BEGIN android-added
-    public native int ioctlAvailable(int fileDescriptor) throws IOException;
+    public native int ioctlAvailable(FileDescriptor fileDescriptor) throws IOException;
     // END android-added
 }
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
index 7c5cf66..876ad78 100644
--- a/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java
@@ -73,24 +73,6 @@
             SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout)
             throws IOException;
 
-    // BEGIN android-removed
-    // public void acceptStreamSocket(FileDescriptor fdServer,
-    //         SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout)
-    //         throws IOException {
-    //     acceptStreamSocketImpl(fdServer, newSocket, fdnewSocket, timeout);
-    // }
-
-    // static native void acceptStreamSocketImpl(FileDescriptor fdServer,
-    //         SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout)
-    //         throws IOException;
-    // END android-removed
-
-    public int availableStream(FileDescriptor fd) throws SocketException {
-        return availableStreamImpl(fd);
-    }
-
-    static native int availableStreamImpl(FileDescriptor aFD) throws SocketException;
-
     /**
      * Associates a local address with a socket.
      *
@@ -230,18 +212,12 @@
     // static native InetAddress getHostByNameImpl(String addr) throws UnknownHostException;
     // END android-removed
 
-    public int getSocketFlags() {
-        return getSocketFlagsImpl();
-    }
-
     public native String byteArrayToIpString(byte[] address)
             throws UnknownHostException;
 
     public native byte[] ipStringToByteArray(String address)
             throws UnknownHostException;
 
-    static native int getSocketFlagsImpl();
-
     public InetAddress getSocketLocalAddress(FileDescriptor fd) {
         return getSocketLocalAddressImpl(fd);
     }
diff --git a/libcore/luni/src/main/native/java_io_File.cpp b/libcore/luni/src/main/native/java_io_File.cpp
index bd81361..586ebbe 100644
--- a/libcore/luni/src/main/native/java_io_File.cpp
+++ b/libcore/luni/src/main/native/java_io_File.cpp
@@ -21,16 +21,17 @@
 #include "ScopedByteArray.h"
 #include "ScopedFd.h"
 
-#include <string.h>
-#include <fcntl.h>
-#include <time.h>
-#include <utime.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <dirent.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
 
 // BEGIN android-note: this file has been extensively rewritten to
 // remove fixed-length buffers, buffer overruns, duplication, and
@@ -105,12 +106,17 @@
     return (access(&path[0], F_OK) == 0);
 }
 
-static jboolean java_io_File_isReadableImpl(JNIEnv* env, jobject, jbyteArray pathBytes) {
+static jboolean java_io_File_canExecuteImpl(JNIEnv* env, jobject, jbyteArray pathBytes) {
+    ScopedByteArray path(env, pathBytes);
+    return (access(&path[0], X_OK) == 0);
+}
+
+static jboolean java_io_File_canReadImpl(JNIEnv* env, jobject, jbyteArray pathBytes) {
     ScopedByteArray path(env, pathBytes);
     return (access(&path[0], R_OK) == 0);
 }
 
-static jboolean java_io_File_isWritableImpl(JNIEnv* env, jobject recv, jbyteArray pathBytes) {
+static jboolean java_io_File_canWriteImpl(JNIEnv* env, jobject recv, jbyteArray pathBytes) {
     ScopedByteArray path(env, pathBytes);
     return (access(&path[0], W_OK) == 0);
 }
@@ -158,17 +164,59 @@
     return (utime(&path[0], &times) == 0);
 }
 
-static jboolean java_io_File_setReadOnlyImpl(JNIEnv* env, jobject recv, jbyteArray pathBytes) {
+static jboolean doChmod(JNIEnv* env, jbyteArray pathBytes, mode_t mask, bool set) {
     ScopedByteArray path(env, pathBytes);
-
     struct stat sb;
     if (stat(&path[0], &sb) == -1) {
         return JNI_FALSE;
     }
+    mode_t newMode = set ? (sb.st_mode | mask) : (sb.st_mode & ~mask);
+    return (chmod(&path[0], newMode) == 0);
+}
 
-    // Strictly, this is set-not-writable (i.e. we leave the execute
-    // bits untouched), but that's deliberate.
-    return (chmod(&path[0], sb.st_mode & ~0222) == 0);
+static jboolean java_io_File_setExecutableImpl(JNIEnv* env, jobject, jbyteArray pathBytes,
+        jboolean set, jboolean ownerOnly) {
+    return doChmod(env, pathBytes, ownerOnly ? S_IXUSR : (S_IXUSR | S_IXGRP | S_IXOTH), set);
+}
+
+static jboolean java_io_File_setReadableImpl(JNIEnv* env, jobject, jbyteArray pathBytes,
+        jboolean set, jboolean ownerOnly) {
+    return doChmod(env, pathBytes, ownerOnly ? S_IRUSR : (S_IRUSR | S_IRGRP | S_IROTH), set);
+}
+
+static jboolean java_io_File_setWritableImpl(JNIEnv* env, jobject, jbyteArray pathBytes,
+        jboolean set, jboolean ownerOnly) {
+    return doChmod(env, pathBytes, ownerOnly ? S_IWUSR : (S_IWUSR | S_IWGRP | S_IWOTH), set);
+}
+
+static bool doStatFs(JNIEnv* env, jbyteArray pathBytes, struct statfs& sb) {
+    ScopedByteArray path(env, pathBytes);
+    int rc = statfs(&path[0], &sb);
+    return (rc != -1);
+}
+
+static jlong java_io_File_getFreeSpace(JNIEnv* env, jobject, jbyteArray pathBytes) {
+    struct statfs sb;
+    if (!doStatFs(env, pathBytes, sb)) {
+        return 0;
+    }
+    return sb.f_bfree * sb.f_bsize; // free block count * block size in bytes.
+}
+
+static jlong java_io_File_getTotalSpace(JNIEnv* env, jobject, jbyteArray pathBytes) {
+    struct statfs sb;
+    if (!doStatFs(env, pathBytes, sb)) {
+        return 0;
+    }
+    return sb.f_blocks * sb.f_bsize; // total block count * block size in bytes.
+}
+
+static jlong java_io_File_getUsableSpace(JNIEnv* env, jobject, jbyteArray pathBytes) {
+    struct statfs sb;
+    if (!doStatFs(env, pathBytes, sb)) {
+        return 0;
+    }
+    return sb.f_bavail * sb.f_bsize; // non-root free block count * block size in bytes.
 }
 
 // Iterates over the filenames in the given directory.
@@ -340,22 +388,28 @@
 
 static JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
-    { "createNewFileImpl",  "([B)Z",  (void*) java_io_File_createNewFileImpl },
-    { "deleteImpl",         "([B)Z",  (void*) java_io_File_deleteImpl },
-    { "existsImpl",         "([B)Z",  (void*) java_io_File_existsImpl },
+    { "canExecuteImpl",     "([B)Z", (void*) java_io_File_canExecuteImpl },
+    { "canReadImpl",        "([B)Z", (void*) java_io_File_canReadImpl },
+    { "canWriteImpl",       "([B)Z", (void*) java_io_File_canWriteImpl },
+    { "createNewFileImpl",  "([B)Z", (void*) java_io_File_createNewFileImpl },
+    { "deleteImpl",         "([B)Z", (void*) java_io_File_deleteImpl },
+    { "existsImpl",         "([B)Z", (void*) java_io_File_existsImpl },
     { "getCanonImpl",       "([B)[B", (void*) java_io_File_getCanonImpl },
+    { "getFreeSpaceImpl",   "([B)J", (void*) java_io_File_getFreeSpace },
     { "getLinkImpl",        "([B)[B", (void*) java_io_File_getLinkImpl },
-    { "isDirectoryImpl",    "([B)Z",  (void*) java_io_File_isDirectoryImpl },
-    { "isFileImpl",         "([B)Z",  (void*) java_io_File_isFileImpl },
-    { "isReadableImpl",     "([B)Z",  (void*) java_io_File_isReadableImpl },
-    { "isWritableImpl",     "([B)Z",  (void*) java_io_File_isWritableImpl },
-    { "lastModifiedImpl",   "([B)J",  (void*) java_io_File_lastModifiedImpl },
-    { "lengthImpl",         "([B)J",  (void*) java_io_File_lengthImpl },
+    { "getTotalSpaceImpl",  "([B)J", (void*) java_io_File_getTotalSpace },
+    { "getUsableSpaceImpl", "([B)J", (void*) java_io_File_getUsableSpace },
+    { "isDirectoryImpl",    "([B)Z", (void*) java_io_File_isDirectoryImpl },
+    { "isFileImpl",         "([B)Z", (void*) java_io_File_isFileImpl },
+    { "lastModifiedImpl",   "([B)J", (void*) java_io_File_lastModifiedImpl },
+    { "lengthImpl",         "([B)J", (void*) java_io_File_lengthImpl },
     { "listImpl",           "([B)[Ljava/lang/String;", (void*) java_io_File_listImpl },
-    { "mkdirImpl",          "([B)Z",  (void*) java_io_File_mkdirImpl },
-    { "renameToImpl",       "([B[B)Z",(void*) java_io_File_renameToImpl },
+    { "mkdirImpl",          "([B)Z", (void*) java_io_File_mkdirImpl },
+    { "renameToImpl",       "([B[B)Z", (void*) java_io_File_renameToImpl },
+    { "setExecutableImpl",  "([BZZ)Z", (void*) java_io_File_setExecutableImpl },
+    { "setReadableImpl",    "([BZZ)Z", (void*) java_io_File_setReadableImpl },
+    { "setWritableImpl",    "([BZZ)Z", (void*) java_io_File_setWritableImpl },
     { "setLastModifiedImpl","([BJ)Z", (void*) java_io_File_setLastModifiedImpl },
-    { "setReadOnlyImpl",    "([B)Z",  (void*) java_io_File_setReadOnlyImpl },
 };
 int register_java_io_File(JNIEnv* env) {
     return jniRegisterNativeMethods(env, "java/io/File",
diff --git a/libcore/luni/src/main/native/java_net_NetworkInterface.cpp b/libcore/luni/src/main/native/java_net_NetworkInterface.cpp
index bf2c89d..724e988 100644
--- a/libcore/luni/src/main/native/java_net_NetworkInterface.cpp
+++ b/libcore/luni/src/main/native/java_net_NetworkInterface.cpp
@@ -18,6 +18,7 @@
 #include "AndroidSystemNatives.h"
 #include "JNIHelp.h"
 #include "jni.h"
+#include "ScopedFd.h"
 
 #include <errno.h>
 #include <netinet/in.h>
diff --git a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
index 3100767..c33cbed 100644
--- a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
+++ b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSFileSystem.cpp
@@ -450,7 +450,7 @@
     return rc;
 }
 
-static jint harmony_io_ioctlAvailable(JNIEnv*env, jobject, jint fd) {
+static jint harmony_io_ioctlAvailable(JNIEnv*env, jobject, jobject fileDescriptor) {
     /*
      * On underlying platforms Android cares about (read "Linux"),
      * ioctl(fd, FIONREAD, &avail) is supposed to do the following:
@@ -476,6 +476,10 @@
      * actually read some amount of data and caused the cursor to be
      * advanced.
      */
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    if (fd == -1) {
+        return -1;
+    }
     int avail = 0;
     int rc = ioctl(fd, FIONREAD, &avail);
     if (rc >= 0) {
@@ -505,7 +509,7 @@
     { "close",              "(I)V",       (void*) harmony_io_close },
     { "fflush",             "(IZ)V",      (void*) harmony_io_fflush },
     { "getAllocGranularity","()I",        (void*) harmony_io_getAllocGranularity },
-    { "ioctlAvailable",     "(I)I",       (void*) harmony_io_ioctlAvailable },
+    { "ioctlAvailable", "(Ljava/io/FileDescriptor;)I", (void*) harmony_io_ioctlAvailable },
     { "lockImpl",           "(IJJIZ)I",   (void*) harmony_io_lockImpl },
     { "openImpl",           "([BI)I",     (void*) harmony_io_openImpl },
     { "readDirect",         "(IIII)J",    (void*) harmony_io_readDirect },
diff --git a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
index 1a8f3a4..a9b040e 100644
--- a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -1828,40 +1828,6 @@
     }
 }
 
-static jint osNetworkSystem_availableStreamImpl(JNIEnv* env, jclass clazz,
-        jobject fileDescriptor) {
-    // LOGD("ENTER availableStreamImpl");
-
-    int handle;
-    if (!jniGetFd(env, fileDescriptor, handle)) {
-        return 0;
-    }
-
-    int result;
-    do {
-        result = selectWait(handle, 1);
-
-        if (SOCKERR_TIMEOUT == result) {
-            // The read operation timed out, so answer 0 bytes available
-            return 0;
-        } else if (SOCKERR_INTERRUPTED == result) {
-            continue;
-        } else if (0 > result) {
-            throwSocketException(env, result);
-            return 0;
-        }
-    } while (SOCKERR_INTERRUPTED == result);
-
-    char message[2048];
-    result = recv(handle, (jbyte *) message, sizeof(message), MSG_PEEK);
-
-    if (0 > result) {
-        jniThrowSocketException(env, errno);
-        return 0;
-    }
-    return result;
-}
-
 static void osNetworkSystem_acceptSocketImpl(JNIEnv* env, jclass,
         jobject serverFileDescriptor,
         jobject newSocket, jobject clientFileDescriptor, jint timeout) {
@@ -2920,13 +2886,6 @@
     }
 }
 
-static jint osNetworkSystem_getSocketFlagsImpl(JNIEnv* env, jclass clazz) {
-    // LOGD("ENTER getSocketFlagsImpl");
-
-    // Not implemented by harmony
-    return 0;
-}
-
 static void osNetworkSystem_socketCloseImpl(JNIEnv* env, jclass clazz,
         jobject fileDescriptor) {
     // LOGD("ENTER socketCloseImpl");
@@ -2962,7 +2921,6 @@
     { "connectStreamWithTimeoutSocketImpl","(Ljava/io/FileDescriptor;IIILjava/net/InetAddress;)V",                     (void*) osNetworkSystem_connectStreamWithTimeoutSocketImpl },
     { "socketBindImpl",                    "(Ljava/io/FileDescriptor;ILjava/net/InetAddress;)V",                       (void*) osNetworkSystem_socketBindImpl                     },
     { "listenStreamSocketImpl",            "(Ljava/io/FileDescriptor;I)V",                                             (void*) osNetworkSystem_listenStreamSocketImpl             },
-    { "availableStreamImpl",               "(Ljava/io/FileDescriptor;)I",                                              (void*) osNetworkSystem_availableStreamImpl                },
     { "acceptSocketImpl",                  "(Ljava/io/FileDescriptor;Ljava/net/SocketImpl;Ljava/io/FileDescriptor;I)V",(void*) osNetworkSystem_acceptSocketImpl                   },
     { "supportsUrgentDataImpl",            "(Ljava/io/FileDescriptor;)Z",                                              (void*) osNetworkSystem_supportsUrgentDataImpl             },
     { "sendUrgentDataImpl",                "(Ljava/io/FileDescriptor;B)V",                                             (void*) osNetworkSystem_sendUrgentDataImpl                 },
@@ -2986,7 +2944,6 @@
     { "getSocketLocalPortImpl",            "(Ljava/io/FileDescriptor;)I",                                              (void*) osNetworkSystem_getSocketLocalPortImpl             },
     { "getSocketOptionImpl",               "(Ljava/io/FileDescriptor;I)Ljava/lang/Object;",                            (void*) osNetworkSystem_getSocketOptionImpl                },
     { "setSocketOptionImpl",               "(Ljava/io/FileDescriptor;ILjava/lang/Object;)V",                           (void*) osNetworkSystem_setSocketOptionImpl                },
-    { "getSocketFlagsImpl",                "()I",                                                                      (void*) osNetworkSystem_getSocketFlagsImpl                 },
     { "socketCloseImpl",                   "(Ljava/io/FileDescriptor;)V",                                              (void*) osNetworkSystem_socketCloseImpl                    },
     { "setInetAddressImpl",                "(Ljava/net/InetAddress;[B)V",                                              (void*) osNetworkSystem_setInetAddressImpl                 },
     { "inheritedChannel",                  "()Ljava/nio/channels/Channel;",                                            (void*) osNetworkSystem_inheritedChannel                   },
diff --git a/libcore/luni/src/test/java/com/google/coretests/XmlReportPrinter.java b/libcore/luni/src/test/java/com/google/coretests/XmlReportPrinter.java
index 315371f..f098b3a 100644
--- a/libcore/luni/src/test/java/com/google/coretests/XmlReportPrinter.java
+++ b/libcore/luni/src/test/java/com/google/coretests/XmlReportPrinter.java
@@ -148,6 +148,7 @@
                     try {
                         stream.close();
                     } catch (IOException ignored) {
+                        ignored.printStackTrace();
                     }
                 }
             }
@@ -224,7 +225,7 @@
                 serializer.attribute(ns, ATTR_MESSAGE, t.getMessage());
             }
             serializer.attribute(ns, ATTR_TYPE, t.getClass().getName());
-            serializer.text(BaseTestRunner.getFilteredTrace(t));
+            serializer.text(sanitize(BaseTestRunner.getFilteredTrace(t)));
             serializer.endTag(ns, type);
 
             serializer.endTag(ns, TESTCASE);
@@ -245,5 +246,12 @@
         @Override public int hashCode() {
             return name.hashCode() ^ className.hashCode();
         }
+
+        /**
+         * Returns the text in a format that is safe for use in an XML document.
+         */
+        private static String sanitize(String text) {
+            return text.replace("\0", "<\\0>");
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/libcore/luni/src/test/java/java/io/FileTest.java b/libcore/luni/src/test/java/java/io/FileTest.java
index 0518c26..423b404 100644
--- a/libcore/luni/src/test/java/java/io/FileTest.java
+++ b/libcore/luni/src/test/java/java/io/FileTest.java
@@ -78,6 +78,7 @@
         // The behavior of the empty filename is an odd mixture.
         File f = new File("");
         // Mostly it behaves like an invalid path...
+        assertFalse(f.canExecute());
         assertFalse(f.canRead());
         assertFalse(f.canWrite());
         try {
@@ -107,7 +108,10 @@
         assertFalse(f.mkdirs());
         assertFalse(f.renameTo(f));
         assertFalse(f.setLastModified(123));
+        assertFalse(f.setExecutable(true));
         assertFalse(f.setReadOnly());
+        assertFalse(f.setReadable(true));
+        assertFalse(f.setWritable(true));
         // ...but sometimes it behaves like "user.dir".
         String cwd = System.getProperty("user.dir");
         assertEquals(new File(cwd), f.getAbsoluteFile());
diff --git a/libcore/luni/src/test/java/java/lang/AllTests.java b/libcore/luni/src/test/java/java/lang/AllTests.java
index d8b7ade..f1c1c72 100644
--- a/libcore/luni/src/test/java/java/lang/AllTests.java
+++ b/libcore/luni/src/test/java/java/lang/AllTests.java
@@ -24,6 +24,7 @@
         TestSuite suite = new TestSuite();
         suite.addTestSuite(java.lang.FloatTest.class);
         suite.addTestSuite(java.lang.ProcessBuilderTest.class);
+        suite.addTestSuite(StringTest.class);
         suite.addTestSuite(SystemTest.class);
         return suite;
     }
diff --git a/libcore/luni/src/test/java/java/lang/StringTest.java b/libcore/luni/src/test/java/java/lang/StringTest.java
new file mode 100644
index 0000000..4b204bb
--- /dev/null
+++ b/libcore/luni/src/test/java/java/lang/StringTest.java
@@ -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.
+ */
+
+package java.lang;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.ReadOnlyBufferException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.util.Arrays;
+import junit.framework.TestCase;
+
+public class StringTest extends TestCase {
+    // The evil decoder keeps hold of the CharBuffer it wrote to.
+    private static final class EvilCharsetDecoder extends CharsetDecoder {
+        private static char[] chars;
+        public EvilCharsetDecoder(Charset cs) {
+            super(cs, 1.0f, 1.0f);
+        }
+        protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
+            chars = out.array();
+            int inLength = in.remaining();
+            for (int i = 0; i < inLength; ++i) {
+                in.put((byte) 'X');
+                out.put('Y');
+            }
+            return CoderResult.UNDERFLOW;
+        }
+        public static void corrupt() {
+            for (int i = 0; i < chars.length; ++i) {
+                chars[i] = '$';
+            }
+        }
+    }
+
+    // The evil encoder tries to write to the CharBuffer it was given to
+    // read from.
+    private static final class EvilCharsetEncoder extends CharsetEncoder {
+        public EvilCharsetEncoder(Charset cs) {
+            super(cs, 1.0f, 1.0f);
+        }
+        protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
+            int inLength = in.remaining();
+            for (int i = 0; i < inLength; ++i) {
+                in.put('x');
+                out.put((byte) 'y');
+            }
+            return CoderResult.UNDERFLOW;
+        }
+    }
+
+    private static final Charset EVIL_CHARSET = new Charset("evil", null) {
+        public boolean contains(Charset charset) { return false; }
+        public CharsetEncoder newEncoder() { return new EvilCharsetEncoder(this); }
+        public CharsetDecoder newDecoder() { return new EvilCharsetDecoder(this); }
+    };
+
+    public void testGetBytes() {
+        Charset cs = Charset.forName("UTF-8");
+        byte[] expected = new byte[] {(byte) 'h', (byte) 'i'};
+        assertTrue(Arrays.equals(expected, "hi".getBytes(cs)));
+    }
+
+    public void testGetBytes_MaliciousCharset() {
+        try {
+            String s = "hi";
+            // Check that our encoder can't write to the input CharBuffer
+            // it was given.
+            s.getBytes(EVIL_CHARSET);
+            fail(); // We shouldn't have got here!
+        } catch (ReadOnlyBufferException expected) {
+            // We caught you trying to be naughty!
+        }
+    }
+
+    public void testStringFromCharset() {
+        Charset cs = Charset.forName("UTF-8");
+        byte[] bytes = new byte[] {(byte) 'h', (byte) 'i'};
+        assertEquals("hi", new String(bytes, cs));
+    }
+
+    public void testStringFromCharset_MaliciousCharset() {
+        Charset cs = EVIL_CHARSET;
+        byte[] bytes = new byte[] {(byte) 'h', (byte) 'i'};
+        final String result = new String(bytes, cs);
+        assertEquals("YY", result); // (Our decoder always outputs 'Y's.)
+        // Check that even if the decoder messes with the output CharBuffer
+        // after we've created a string from it, it doesn't affect the string.
+        EvilCharsetDecoder.corrupt();
+        assertEquals("YY", result);
+    }
+}
diff --git a/libcore/luni/src/test/java/java/math/AllTests.java b/libcore/luni/src/test/java/java/math/AllTests.java
new file mode 100644
index 0000000..f182e01
--- /dev/null
+++ b/libcore/luni/src/test/java/java/math/AllTests.java
@@ -0,0 +1,28 @@
+/*
+ * 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 java.math;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AllTests {
+    public static final Test suite() {
+        TestSuite suite = new TestSuite();
+        suite.addTestSuite(java.math.BigIntegerTest.class);
+        return suite;
+    }
+}
diff --git a/libcore/luni/src/test/java/java/math/BigIntegerTest.java b/libcore/luni/src/test/java/java/math/BigIntegerTest.java
new file mode 100644
index 0000000..831ed62
--- /dev/null
+++ b/libcore/luni/src/test/java/java/math/BigIntegerTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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 java.math;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import java.math.BigInteger;
+import java.util.Locale;
+
+public class BigIntegerTest extends junit.framework.TestCase {
+    // http://code.google.com/p/android/issues/detail?id=7036
+    public void test_invalidBigIntegerStringConversions() {
+        // Check we don't disallow related reasonable strings...
+        new BigInteger("1", 10);
+        new BigInteger("1a", 16);
+        new BigInteger("-1", 10);
+        new BigInteger("-1a", 16);
+        // Now check the invalid cases...
+        try {
+            new BigInteger("+1"); // no positive sign allowed.
+            fail();
+        } catch (NumberFormatException expected) {
+        }
+        try {
+            new BigInteger("-a"); // no digits from other bases.
+            fail();
+        } catch (NumberFormatException expected) {
+        }
+        try {
+            new BigInteger("-1a"); // no trailing digits from other bases.
+            fail();
+        } catch (NumberFormatException expected) {
+        }
+        try {
+            new BigInteger("-1 hello"); // no trailing junk at all.
+            fail();
+        } catch (NumberFormatException expected) {
+        }
+        try {
+            new BigInteger("--1"); // only one sign.
+            fail();
+        } catch (NumberFormatException expected) {
+        }
+        try {
+            new BigInteger(""); // at least one digit.
+            fail();
+        } catch (NumberFormatException expected) {
+        }
+        try {
+            new BigInteger("-"); // at least one digit, even after a sign.
+            fail();
+        } catch (NumberFormatException expected) {
+        }
+    }
+}
diff --git a/libcore/luni/src/test/java/java/util/FormatterTest.java b/libcore/luni/src/test/java/java/util/FormatterTest.java
index 1722e67..81c8a36 100644
--- a/libcore/luni/src/test/java/java/util/FormatterTest.java
+++ b/libcore/luni/src/test/java/java/util/FormatterTest.java
@@ -16,6 +16,7 @@
 
 package java.util;
 
+import java.math.BigDecimal;
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
@@ -42,4 +43,32 @@
         // ...without screwing up conversions that don't take an argument.
         assertEquals("%", String.format(Locale.US, "%%"));
     }
+    
+    // Alleged regression tests for historical bugs. (It's unclear whether the bugs were in
+    // BigDecimal or Formatter.)
+    public void test_BigDecimalFormatting() throws Exception {
+        BigDecimal[] input = new BigDecimal[] {
+            new BigDecimal("20.00000"),
+            new BigDecimal("20.000000"),
+            new BigDecimal(".2"),
+            new BigDecimal("2"),
+            new BigDecimal("-2"),
+            new BigDecimal("200000000000000000000000"),
+            new BigDecimal("20000000000000000000000000000000000000000000000000")
+        };
+        String[] output = new String[] {
+            "20.00",
+            "20.00",
+            "0.20",
+            "2.00",
+            "-2.00",
+            "200000000000000000000000.00",
+            "20000000000000000000000000000000000000000000000000.00"
+        };
+        for (int i = 0; i < input.length; ++i) {
+            String result = String.format("%.2f", input[i]);
+            assertEquals("input=\"" + input[i] + "\", " + ",expected=" + output[i] + ",actual=" + result,
+                    output[i], result);
+        }
+    }
 }
diff --git a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/MathTest.java b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/MathTest.java
index 02bed3c..4ff0a09 100644
--- a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/MathTest.java
+++ b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/MathTest.java
@@ -17,247 +17,107 @@
 
 package org.apache.harmony.luni.tests.java.lang;
 
-import dalvik.annotation.TestLevel;
-import dalvik.annotation.TestTargetNew;
-import dalvik.annotation.TestTargetClass;
-
-@TestTargetClass(Math.class) 
 public class MathTest extends junit.framework.TestCase {
 
-    double HYP = Math.sqrt(2.0);
+	double HYP = Math.sqrt(2.0);
 
-    double OPP = 1.0;
+	double OPP = 1.0;
 
-    double ADJ = 1.0;
+	double ADJ = 1.0;
 
-    /* Required to make previous preprocessor flags work - do not remove */
-    int unused = 0;
+	/* Required to make previous preprocessor flags work - do not remove */
+	int unused = 0;
 
-    public static void assertEquals(String message, double expected, double actual, double delta) {
-        if (delta == 0D)
-            junit.framework.Assert.assertEquals(message, expected, actual, Math.ulp(expected));
-        else
-            junit.framework.Assert.assertEquals(message, expected, actual, delta);
-    }
+	/**
+	 * @tests java.lang.Math#abs(double)
+	 */
+	public void test_absD() {
+		// Test for method double java.lang.Math.abs(double)
 
-    public static void assertEquals(String message, float expected, float actual, float delta) {
-        if (delta == 0F)
-            junit.framework.Assert.assertEquals(message, expected, actual, Math.ulp(expected));
-        else
-            junit.framework.Assert.assertEquals(message, expected, actual, delta);
-    }
-    
-    /**
-     * @tests java.lang.Math#abs(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "abs",
-        args = {double.class}
-    )
-    public void test_absD() {
-        // Test for method double java.lang.Math.abs(double)
-        assertTrue("Incorrect double abs value",
-                (Math.abs(-1908.8976) == 1908.8976));
-        assertTrue("Incorrect double abs value",
-                (Math.abs(1908.8976) == 1908.8976));
-        assertEquals(0.0, Math.abs(0.0));
-        assertEquals(0.0, Math.abs(-0.0));
-        assertEquals(Double.POSITIVE_INFINITY, 
-                                            Math.abs(Double.POSITIVE_INFINITY));
-        assertEquals(Double.POSITIVE_INFINITY, 
-                                            Math.abs(Double.NEGATIVE_INFINITY));
-        
-        assertEquals(Double.NaN, Math.abs(Double.NaN));        
-    }
+		assertTrue("Incorrect double abs value",
+				(Math.abs(-1908.8976) == 1908.8976));
+		assertTrue("Incorrect double abs value",
+				(Math.abs(1908.8976) == 1908.8976));
+	}
 
-    /**
-     * @tests java.lang.Math#abs(float)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "abs",
-        args = {float.class}
-    )
-    public void test_absF() {
-        // Test for method float java.lang.Math.abs(float)
-        assertTrue("Incorrect float abs value",
-                (Math.abs(-1908.8976f) == 1908.8976f));
-        assertTrue("Incorrect float abs value",
-                (Math.abs(1908.8976f) == 1908.8976f));
-        
-        assertEquals(0.0f, Math.abs(0.0f));
-        assertEquals(0.0f, Math.abs(-0.0f));
-        assertEquals(Float.POSITIVE_INFINITY, 
-                                            Math.abs(Float.POSITIVE_INFINITY));
-        assertEquals(Float.POSITIVE_INFINITY, 
-                                            Math.abs(Float.NEGATIVE_INFINITY));
-        
-        assertEquals(Float.NaN, Math.abs(Float.NaN));
-    }
+	/**
+	 * @tests java.lang.Math#abs(float)
+	 */
+	public void test_absF() {
+		// Test for method float java.lang.Math.abs(float)
+		assertTrue("Incorrect float abs value",
+				(Math.abs(-1908.8976f) == 1908.8976f));
+		assertTrue("Incorrect float abs value",
+				(Math.abs(1908.8976f) == 1908.8976f));
+	}
 
-    /**
-     * @tests java.lang.Math#abs(int)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "abs",
-        args = {int.class}
-    )
-    public void test_absI() {
-        // Test for method int java.lang.Math.abs(int)
-        assertTrue("Incorrect int abs value", (Math.abs(-1908897) == 1908897));
-        assertTrue("Incorrect int abs value", (Math.abs(1908897) == 1908897));
-        
-        assertEquals(Integer.MIN_VALUE, Math.abs(Integer.MIN_VALUE));
-    }
+	/**
+	 * @tests java.lang.Math#abs(int)
+	 */
+	public void test_absI() {
+		// Test for method int java.lang.Math.abs(int)
+		assertTrue("Incorrect int abs value", (Math.abs(-1908897) == 1908897));
+		assertTrue("Incorrect int abs value", (Math.abs(1908897) == 1908897));
+	}
 
-    /**
-     * @tests java.lang.Math#abs(long)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "abs",
-        args = {long.class}
-    )
-    public void test_absJ() {
-        // Test for method long java.lang.Math.abs(long)
-        assertTrue("Incorrect long abs value",
-                (Math.abs(-19088976000089L) == 19088976000089L));
-        assertTrue("Incorrect long abs value",
-                (Math.abs(19088976000089L) == 19088976000089L));
-        
-        assertEquals(Long.MIN_VALUE, Math.abs(Long.MIN_VALUE));        
-    }
+	/**
+	 * @tests java.lang.Math#abs(long)
+	 */
+	public void test_absJ() {
+		// Test for method long java.lang.Math.abs(long)
+		assertTrue("Incorrect long abs value",
+				(Math.abs(-19088976000089L) == 19088976000089L));
+		assertTrue("Incorrect long abs value",
+				(Math.abs(19088976000089L) == 19088976000089L));
+	}
 
-    /**
-     * @tests java.lang.Math#acos(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "acos",
-        args = {double.class}
-    )
-    public void test_acosD() {
-        // Test for method double java.lang.Math.acos(double)
-        double r = Math.cos(Math.acos(ADJ / HYP));
-        long lr = Double.doubleToLongBits(r);
-        long t = Double.doubleToLongBits(ADJ / HYP);
-        assertTrue("Returned incorrect arc cosine", lr == t || (lr + 1) == t
-                || (lr - 1) == t);
-        
-        assertEquals(Double.NaN, Math.acos(Double.MAX_VALUE));
-        assertEquals(Double.NaN, Math.acos(Double.NaN));
-    }
+	/**
+	 * @tests java.lang.Math#acos(double)
+	 */
+	public void test_acosD() {
+		// Test for method double java.lang.Math.acos(double)
+		double r = Math.cos(Math.acos(ADJ / HYP));
+		long lr = Double.doubleToLongBits(r);
+		long t = Double.doubleToLongBits(ADJ / HYP);
+		assertTrue("Returned incorrect arc cosine", lr == t || (lr + 1) == t
+				|| (lr - 1) == t);
+	}
 
-    /**
-     * @tests java.lang.Math#asin(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "asin",
-        args = {double.class}
-    )
-    public void test_asinD() {
-        // Test for method double java.lang.Math.asin(double)
-        double r = Math.sin(Math.asin(OPP / HYP));
-        long lr = Double.doubleToLongBits(r);
-        long t = Double.doubleToLongBits(OPP / HYP);
-        assertTrue("Returned incorrect arc sine", lr == t || (lr + 1) == t
-                || (lr - 1) == t);
-        
-        assertEquals(Double.NaN, Math.asin(Double.MAX_VALUE));
-        assertEquals(Double.NaN, Math.asin(Double.NaN));
-        assertEquals(0, Math.asin(0), 0);
-        assertEquals(-0, Math.asin(-0), 0);        
-    }
+	/**
+	 * @tests java.lang.Math#asin(double)
+	 */
+	public void test_asinD() {
+		// Test for method double java.lang.Math.asin(double)
+		double r = Math.sin(Math.asin(OPP / HYP));
+		long lr = Double.doubleToLongBits(r);
+		long t = Double.doubleToLongBits(OPP / HYP);
+		assertTrue("Returned incorrect arc sine", lr == t || (lr + 1) == t
+				|| (lr - 1) == t);
+	}
 
-    /**
-     * @tests java.lang.Math#atan(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "atan",
-        args = {double.class}
-    )
-    public void test_atanD() {
-        // Test for method double java.lang.Math.atan(double)
-        double answer = Math.tan(Math.atan(1.0));
-        assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
-                && answer >= 9.9999999999999983E-1);
-        
-        assertEquals(Double.NaN, Math.atan(Double.NaN));
-        assertEquals(0.0, Math.atan(0.0), 0.0);
-        assertEquals(-0.0, Math.atan(-0.0), 0.0);
-    }
+	/**
+	 * @tests java.lang.Math#atan(double)
+	 */
+	public void test_atanD() {
+		// Test for method double java.lang.Math.atan(double)
+		double answer = Math.tan(Math.atan(1.0));
+		assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
+				&& answer >= 9.9999999999999983E-1);
+	}
 
-    /**
-     * @tests java.lang.Math#atan2(double, double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "atan2",
-        args = {double.class, double.class}
-    )
-    public void test_atan2DD() {
-        double pi = 3.141592653589793;
-        // Test for method double java.lang.Math.atan2(double, double)
-        double answer = Math.atan(Math.tan(1.0));
-        assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
-                && answer >= 9.9999999999999983E-1);
-        
-        assertEquals(Double.NaN, Math.atan2(Double.NaN, 1.0));
-        assertEquals(Double.NaN, Math.atan2(1.0, Double.NaN));
-        
-        assertEquals(0.0, Math.atan2(0, 1));
-        assertEquals(0.0, Math.atan2(1, Double.POSITIVE_INFINITY));
-        
-        assertEquals(-0.0, Math.atan2(-0.0, 1.0));
-        assertEquals(-0.0, Math.atan2(-1.0, Double.POSITIVE_INFINITY));
-        
-        assertEquals(pi, Math.atan2(0.0, -1.0));
-        assertEquals(pi, Math.atan2(1.0, Double.NEGATIVE_INFINITY));       
-        
-        assertEquals(-pi, Math.atan2(-0.0, -1.0));
-        assertEquals(-pi, Math.atan2(-1.0, Double.NEGATIVE_INFINITY)); 
-        
-        assertEquals(pi/2, Math.atan2(1.0, 0.0));
-        assertEquals(pi/2, Math.atan2(1.0, -0.0));
-        
-        assertEquals(pi/2, Math.atan2(Double.POSITIVE_INFINITY, 1));
-        assertEquals(pi/2, Math.atan2(Double.POSITIVE_INFINITY, -1));     
-        
-        assertEquals(-pi/2, Math.atan2(-1, 0));
-        assertEquals(-pi/2, Math.atan2(-1, -0));        
-        assertEquals(-pi/2, Math.atan2(Double.NEGATIVE_INFINITY, 1)); 
-        
-        assertEquals(pi/4, Math.atan2(Double.POSITIVE_INFINITY, 
-                                                     Double.POSITIVE_INFINITY));
-        assertEquals(3*pi/4, Math.atan2(Double.POSITIVE_INFINITY, 
-                                                     Double.NEGATIVE_INFINITY));    
-        assertEquals(-pi/4, Math.atan2(Double.NEGATIVE_INFINITY, 
-                                                     Double.POSITIVE_INFINITY)); 
-        assertEquals(-3*pi/4, Math.atan2(Double.NEGATIVE_INFINITY, 
-                                                     Double.NEGATIVE_INFINITY));        
-    }
+	/**
+	 * @tests java.lang.Math#atan2(double, double)
+	 */
+	public void test_atan2DD() {
+		// Test for method double java.lang.Math.atan2(double, double)
+		double answer = Math.atan(Math.tan(1.0));
+		assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
+				&& answer >= 9.9999999999999983E-1);
+	}
     
      /**
      * @tests java.lang.Math#cbrt(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "cbrt",
-        args = {double.class}
-    )
     public void test_cbrt_D() {
         //Test for special situations
         assertTrue("Should return Double.NaN", Double.isNaN(Math
@@ -269,11 +129,11 @@
                 Double.NEGATIVE_INFINITY, Math
                         .cbrt(Double.NEGATIVE_INFINITY), 0D);
         assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
-                .cbrt(0.0)));
-        assertEquals(Double.doubleToLongBits(+0.0), Double.doubleToLongBits(Math
-                .cbrt(+0.0)));
-        assertEquals(Double.doubleToLongBits(-0.0), Double.doubleToLongBits(Math
-                .cbrt(-0.0)));
+				.cbrt(0.0)));
+		assertEquals(Double.doubleToLongBits(+0.0), Double.doubleToLongBits(Math
+				.cbrt(+0.0)));
+		assertEquals(Double.doubleToLongBits(-0.0), Double.doubleToLongBits(Math
+				.cbrt(-0.0)));
 
         assertEquals("Should return 3.0", 3.0, Math.cbrt(27.0), 0D);
         assertEquals("Should return 23.111993172558684", 23.111993172558684,
@@ -290,62 +150,173 @@
         assertEquals("Should return -0.01", -0.01, Math.cbrt(-0.000001), 0D);
     }
 
-    /**
-     * @tests java.lang.Math#ceil(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "ceil",
-        args = {double.class}
-    )
-    public void test_ceilD() {
-        // Test for method double java.lang.Math.ceil(double)
+	/**
+	 * @tests java.lang.Math#ceil(double)
+	 */
+	public void test_ceilD() {
+		// Test for method double java.lang.Math.ceil(double)
                 assertEquals("Incorrect ceiling for double",
                              79, Math.ceil(78.89), 0);
-        assertEquals("Incorrect ceiling for double",
+		assertEquals("Incorrect ceiling for double",
                              -78, Math.ceil(-78.89), 0);
-        
-        assertEquals("Incorrect ceiling for double",
-                -78, Math.ceil(-78), 0);
-        
-        double [] args = {0.0, -0.0, Double.NaN, Double.POSITIVE_INFINITY, 
-                Double.NEGATIVE_INFINITY};
-        for(int i = 0; i < args.length; i++) {
-            assertEquals(args[i], Math.ceil(args[i]));
+	}
+	
+	/**
+     * cases for test_copySign_DD in MathTest/StrictMathTest
+     */
+    static final double[] COPYSIGN_DD_CASES = new double[] {
+            Double.POSITIVE_INFINITY, Double.MAX_VALUE, 3.4E302, 2.3,
+            Double.MIN_NORMAL, Double.MIN_NORMAL / 2, Double.MIN_VALUE, +0.0,
+            0.0, -0.0, -Double.MIN_VALUE, -Double.MIN_NORMAL / 2,
+            -Double.MIN_NORMAL, -4.5, -3.4E102, -Double.MAX_VALUE,
+            Double.NEGATIVE_INFINITY };
+
+    /**
+     * @tests {@link java.lang.Math#copySign(double, double)}
+     * @since 1.6
+     * 
+     */
+    @SuppressWarnings("boxing")
+    public void test_copySign_DD() {
+        for (int i = 0; i < COPYSIGN_DD_CASES.length; i++) {
+            final double magnitude = COPYSIGN_DD_CASES[i];
+            final long absMagnitudeBits = Double.doubleToLongBits(Math
+                    .abs(magnitude));
+            final long negMagnitudeBits = Double.doubleToLongBits(-Math
+                    .abs(magnitude));
+
+            // cases for NaN
+            assertEquals("If the sign is NaN, the result should be positive.",
+                    absMagnitudeBits, Double.doubleToLongBits(Math.copySign(
+                            magnitude, Double.NaN)));
+            assertTrue("The result should be NaN.", Double.isNaN(Math.copySign(
+                    Double.NaN, magnitude)));
+
+            for (int j = 0; j < COPYSIGN_DD_CASES.length; j++) {
+                final double sign = COPYSIGN_DD_CASES[j];
+                final long resultBits = Double.doubleToLongBits(Math.copySign(
+                        magnitude, sign));
+
+                if (sign > 0 || Double.valueOf(+0.0).equals(sign)
+                        || Double.valueOf(0.0).equals(sign)) {
+                    assertEquals(
+                            "If the sign is positive, the result should be positive.",
+                            absMagnitudeBits, resultBits);
+                }
+                if (sign < 0 || Double.valueOf(-0.0).equals(sign)) {
+                    assertEquals(
+                            "If the sign is negative, the result should be negative.",
+                            negMagnitudeBits, resultBits);
+                }
+            }
         }
-        assertEquals(-0.0, Math.ceil(-0.5));
+
+        assertTrue("The result should be NaN.", Double.isNaN(Math.copySign(
+                Double.NaN, Double.NaN)));
+
+        try {
+            Math.copySign((Double) null, 2.3);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            Math.copySign(2.3, (Double) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            Math.copySign((Double) null, (Double) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
     }
 
     /**
-     * @tests java.lang.Math#cos(double)
+     * cases for test_copySign_FF in MathTest/StrictMathTest
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "cos",
-        args = {double.class}
-    )
-    public void test_cosD() {
-        // Test for method double java.lang.Math.cos(double)
-        assertEquals("Incorrect answer", 1.0, Math.cos(0), 0D);
-        assertEquals("Incorrect answer", 0.5403023058681398, Math.cos(1), 0D);
-        double [] args = {Double.NaN, Double.POSITIVE_INFINITY, 
-                          Double.NEGATIVE_INFINITY};
-        for(int i = 0; i < args.length; i++) {
-            assertEquals(args[i], Math.ceil(args[i]));
-        }        
+    static final float[] COPYSIGN_FF_CASES = new float[] {
+            Float.POSITIVE_INFINITY, Float.MAX_VALUE, 3.4E12f, 2.3f,
+            Float.MIN_NORMAL, Float.MIN_NORMAL / 2, Float.MIN_VALUE, +0.0f,
+            0.0f, -0.0f, -Float.MIN_VALUE, -Float.MIN_NORMAL / 2,
+            -Float.MIN_NORMAL, -4.5f, -5.6442E21f, -Float.MAX_VALUE,
+            Float.NEGATIVE_INFINITY };
+
+    /**
+     * @tests {@link java.lang.Math#copySign(float, float)}
+     * @since 1.6
+     */
+    @SuppressWarnings("boxing")
+    public void test_copySign_FF() {
+        for (int i = 0; i < COPYSIGN_FF_CASES.length; i++) {
+            final float magnitude = COPYSIGN_FF_CASES[i];
+            final int absMagnitudeBits = Float.floatToIntBits(Math
+                    .abs(magnitude));
+            final int negMagnitudeBits = Float.floatToIntBits(-Math
+                    .abs(magnitude));
+
+            // cases for NaN
+            assertEquals("If the sign is NaN, the result should be positive.",
+                    absMagnitudeBits, Float.floatToIntBits(Math.copySign(
+                            magnitude, Float.NaN)));
+            assertTrue("The result should be NaN.", Float.isNaN(Math.copySign(
+                    Float.NaN, magnitude)));
+
+            for (int j = 0; j < COPYSIGN_FF_CASES.length; j++) {
+                final float sign = COPYSIGN_FF_CASES[j];
+                final int resultBits = Float.floatToIntBits(Math.copySign(
+                        magnitude, sign));
+                if (sign > 0 || Float.valueOf(+0.0f).equals(sign)
+                        || Float.valueOf(0.0f).equals(sign)) {
+                    assertEquals(
+                            "If the sign is positive, the result should be positive.",
+                            absMagnitudeBits, resultBits);
+                }
+                if (sign < 0 || Float.valueOf(-0.0f).equals(sign)) {
+                    assertEquals(
+                            "If the sign is negative, the result should be negative.",
+                            negMagnitudeBits, resultBits);
+                }
+            }
+        }
+
+        assertTrue("The result should be NaN.", Float.isNaN(Math.copySign(
+                Float.NaN, Float.NaN)));
+
+        try {
+            Math.copySign((Float) null, 2.3f);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            Math.copySign(2.3f, (Float) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            Math.copySign((Float) null, (Float) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
     }
 
+	/**
+	 * @tests java.lang.Math#cos(double)
+	 */
+	public void test_cosD() {
+		// Test for method double java.lang.Math.cos(double)
+		assertEquals("Incorrect answer", 1.0, Math.cos(0), 0D);
+		assertEquals("Incorrect answer", 0.5403023058681398, Math.cos(1), 0D);
+	}
+
     /**
      * @tests java.lang.Math#cosh(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "cosh",
-        args = {double.class}
-    )
     public void test_cosh_D() {
         // Test for special situations
         assertTrue(Double.isNaN(Math.cosh(Double.NaN)));
@@ -372,40 +343,21 @@
         assertEquals("Should return 1.0", 1.0, Math.cosh(Double.MIN_VALUE), 0D);
     }
     
-    /**
-     * @tests java.lang.Math#exp(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "exp",
-        args = {double.class}
-    )
-    public void test_expD() {
-        // Test for method double java.lang.Math.exp(double)
-        assertTrue("Incorrect answer returned for simple power", Math.abs(Math
-                .exp(4D)
-                - Math.E * Math.E * Math.E * Math.E) < 0.1D);
-        assertTrue("Incorrect answer returned for larger power", Math.log(Math
-                .abs(Math.exp(5.5D)) - 5.5D) < 10.0D);
-        
-        assertEquals("Incorrect returned value for NaN", 
-                                              Double.NaN, Math.exp(Double.NaN));
-        assertEquals("Incorrect returned value for positive infinity", 
-                  Double.POSITIVE_INFINITY, Math.exp(Double.POSITIVE_INFINITY));
-        assertEquals("Incorrect returned value for negative infinity", 
-                                      0, Math.exp(Double.NEGATIVE_INFINITY), 0);        
-    }
+	/**
+	 * @tests java.lang.Math#exp(double)
+	 */
+	public void test_expD() {
+		// Test for method double java.lang.Math.exp(double)
+		assertTrue("Incorrect answer returned for simple power", Math.abs(Math
+				.exp(4D)
+				- Math.E * Math.E * Math.E * Math.E) < 0.1D);
+		assertTrue("Incorrect answer returned for larger power", Math.log(Math
+				.abs(Math.exp(5.5D)) - 5.5D) < 10.0D);
+	}
     
     /**
      * @tests java.lang.Math#expm1(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "expm1",
-        args = {double.class}
-    )
     public void test_expm1_D() {
         // Test for special cases
         assertTrue("Should return NaN", Double.isNaN(Math.expm1(Double.NaN)));
@@ -414,11 +366,11 @@
         assertEquals("Should return -1.0", -1.0, Math
                 .expm1(Double.NEGATIVE_INFINITY), 0D);
         assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
-                .expm1(0.0)));
-        assertEquals(Double.doubleToLongBits(+0.0), Double
-                .doubleToLongBits(Math.expm1(+0.0)));
-        assertEquals(Double.doubleToLongBits(-0.0), Double
-                .doubleToLongBits(Math.expm1(-0.0)));
+				.expm1(0.0)));
+		assertEquals(Double.doubleToLongBits(+0.0), Double
+				.doubleToLongBits(Math.expm1(+0.0)));
+		assertEquals(Double.doubleToLongBits(-0.0), Double
+				.doubleToLongBits(Math.expm1(-0.0)));
 
         assertEquals("Should return -9.999950000166666E-6",
                 -9.999950000166666E-6, Math.expm1(-0.00001), 0D);
@@ -436,36 +388,123 @@
     /**
      * @tests java.lang.Math#floor(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "floor",
-        args = {double.class}
-    )
     public void test_floorD() {
-        // Test for method double java.lang.Math.floor(double)
-                assertEquals("Incorrect floor for double",
-                             78, Math.floor(78.89), 0);
-        assertEquals("Incorrect floor for double",
-                             -79, Math.floor(-78.89), 0);
-        assertEquals("Incorrect floor for integer",
-                              -78, Math.floor(-78), 0);
-        double [] args = {0, -0, Double.NaN, Double.POSITIVE_INFINITY, 
-                Double.NEGATIVE_INFINITY};
-        for(int i = 0; i < args.length; i++) {
-            assertEquals(args[i], Math.floor(args[i]));
-        }        
+        assertEquals("Incorrect floor for int", 42, Math.floor(42), 0);
+        assertEquals("Incorrect floor for -int", -2, Math.floor(-2), 0);
+        assertEquals("Incorrect floor for zero", 0d, Math.floor(0d), 0);
+
+        assertEquals("Incorrect floor for +double", 78, Math.floor(78.89), 0);
+        assertEquals("Incorrect floor for -double", -79, Math.floor(-78.89), 0);
+        assertEquals("floor large +double", 3.7314645675925406E19, Math.floor(3.7314645675925406E19), 0);
+        assertEquals("floor large -double", -8.173521839218E12, Math.floor(-8.173521839218E12), 0);
+        assertEquals("floor small double", 0.0d, Math.floor(1.11895241315E-102), 0);
+
+        // Compare toString representations here since -0.0 = +0.0, and
+        // NaN != NaN and we need to distinguish
+        assertEquals("Floor failed for NaN",
+                Double.toString(Double.NaN), Double.toString(Math.floor(Double.NaN)));
+        assertEquals("Floor failed for +0.0",
+                Double.toString(+0.0d), Double.toString(Math.floor(+0.0d)));
+        assertEquals("Floor failed for -0.0",
+                Double.toString(-0.0d), Double.toString(Math.floor(-0.0d)));
+        assertEquals("Floor failed for +infinity",
+                Double.toString(Double.POSITIVE_INFINITY), Double.toString(Math.floor(Double.POSITIVE_INFINITY)));
+        assertEquals("Floor failed for -infinity",
+                Double.toString(Double.NEGATIVE_INFINITY), Double.toString(Math.floor(Double.NEGATIVE_INFINITY)));
+    }
+	
+	/**
+     * cases for test_getExponent_D in MathTest/StrictMathTest
+     */
+    static final double GETEXPONENT_D_CASES[] = new double[] {
+            Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY,
+            Double.MAX_VALUE, -Double.MAX_VALUE, 2.342E231, -2.342E231, 2800.0,
+            -2800.0, 5.323, -5.323, 1.323, -1.323, 0.623, -0.623, 0.323,
+            -0.323, Double.MIN_NORMAL * 24, -Double.MIN_NORMAL * 24,
+            Double.MIN_NORMAL, -Double.MIN_NORMAL, Double.MIN_NORMAL / 2,
+            -Double.MIN_NORMAL / 2, Double.MIN_VALUE, -Double.MIN_VALUE, +0.0,
+            0.0, -0.0, Double.NaN };
+
+    /**
+     * result for test_getExponent_D in MathTest/StrictMathTest
+     */
+    static final int GETEXPONENT_D_RESULTS[] = new int[] {
+            Double.MAX_EXPONENT + 1, Double.MAX_EXPONENT + 1,
+            Double.MAX_EXPONENT, Double.MAX_EXPONENT, 768, 768, 11, 11, 2, 2,
+            0, 0, -1, -1, -2, -2, -1018, -1018, Double.MIN_EXPONENT,
+            Double.MIN_EXPONENT, Double.MIN_EXPONENT - 1,
+            Double.MIN_EXPONENT - 1, Double.MIN_EXPONENT - 1,
+            Double.MIN_EXPONENT - 1, Double.MIN_EXPONENT - 1,
+            Double.MIN_EXPONENT - 1, Double.MIN_EXPONENT - 1,
+            Double.MAX_EXPONENT + 1 };
+
+    /**
+     * @tests {@link java.lang.Math#getExponent(double)}
+     * @since 1.6
+     */
+    @SuppressWarnings("boxing")
+    public void test_getExponent_D() {
+        for (int i = 0; i < GETEXPONENT_D_CASES.length; i++) {
+            final double number = GETEXPONENT_D_CASES[i];
+            final int result = GETEXPONENT_D_RESULTS[i];
+            assertEquals("Wrong result of getExponent(double).", result, Math
+                    .getExponent(number));
+        }
+
+        try {
+            Math.getExponent((Double) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+    }
+
+    /**
+     * cases for test_getExponent_F in MathTest/StrictMathTest
+     */
+    static final float GETEXPONENT_F_CASES[] = new float[] {
+            Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.MAX_VALUE,
+            -Float.MAX_VALUE, 3.4256E23f, -3.4256E23f, 2800.0f, -2800.0f,
+            5.323f, -5.323f, 1.323f, -1.323f, 0.623f, -0.623f, 0.323f, -0.323f,
+            Float.MIN_NORMAL * 24, -Float.MIN_NORMAL * 24, Float.MIN_NORMAL,
+            -Float.MIN_NORMAL, Float.MIN_NORMAL / 2, -Float.MIN_NORMAL / 2,
+            Float.MIN_VALUE, -Float.MIN_VALUE, +0.0f, 0.0f, -0.0f, Float.NaN,1,Float.MIN_NORMAL * 1.5f };
+
+    /**
+     * result for test_getExponent_F in MathTest/StrictMathTest
+     */
+    static final int GETEXPONENT_F_RESULTS[] = new int[] {
+            Float.MAX_EXPONENT + 1, Float.MAX_EXPONENT + 1, Float.MAX_EXPONENT,
+            Float.MAX_EXPONENT, 78, 78, 11, 11, 2, 2, 0, 0, -1, -1, -2, -2,
+            -122, -122, Float.MIN_EXPONENT, Float.MIN_EXPONENT,
+            Float.MIN_EXPONENT - 1, Float.MIN_EXPONENT - 1,
+            Float.MIN_EXPONENT - 1, Float.MIN_EXPONENT - 1,
+            Float.MIN_EXPONENT - 1, Float.MIN_EXPONENT - 1,
+            Float.MIN_EXPONENT - 1, Float.MAX_EXPONENT + 1,0,Float.MIN_EXPONENT };
+    
+    /**
+     * @tests {@link java.lang.Math#getExponent(float)}
+     * @since 1.6
+     */
+    @SuppressWarnings("boxing")
+    public void test_getExponent_F() {
+        for (int i = 0; i < GETEXPONENT_F_CASES.length; i++) {
+            final float number = GETEXPONENT_F_CASES[i];
+            final int result = GETEXPONENT_F_RESULTS[i];
+            assertEquals("Wrong result of getExponent(float).", result, Math
+                    .getExponent(number));
+        }
+        try {
+            Math.getExponent((Float) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
     }
     
     /**
      * @tests java.lang.Math#hypot(double, double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "hypot",
-        args = {double.class, double.class}
-    )
     public void test_hypot_DD() {
         // Test for special cases
         assertEquals("Should return POSITIVE_INFINITY",
@@ -501,63 +540,34 @@
                 -5413.7185, Double.MIN_VALUE), 0D);
     }
 
-    /**
-     * @tests java.lang.Math#IEEEremainder(double, double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "IEEEremainder",
-        args = {double.class, double.class}
-    )
-    public void test_IEEEremainderDD() {
-        // Test for method double java.lang.Math.IEEEremainder(double, double)
-        assertEquals("Incorrect remainder returned",
-                0.0, Math.IEEEremainder(1.0, 1.0), 0D);
-        assertTrue("Incorrect remainder returned", Math.IEEEremainder(1.32,
-                89.765) >= 1.4705063220631647E-2
-                || Math.IEEEremainder(1.32, 89.765) >= 1.4705063220631649E-2);
-        
-        assertEquals(Double.NaN, Math.IEEEremainder(Double.NaN, Double.NaN));
-        assertEquals(Double.NaN, Math.IEEEremainder(Double.NaN, 1.0));    
-        assertEquals(Double.NaN, Math.IEEEremainder(1.0, Double.NaN)); 
+	/**
+	 * @tests java.lang.Math#IEEEremainder(double, double)
+	 */
+	public void test_IEEEremainderDD() {
+		// Test for method double java.lang.Math.IEEEremainder(double, double)
+		assertEquals("Incorrect remainder returned",
+				0.0, Math.IEEEremainder(1.0, 1.0), 0D);
+		assertTrue("Incorrect remainder returned", Math.IEEEremainder(1.32,
+				89.765) >= 1.4705063220631647E-2
+				|| Math.IEEEremainder(1.32, 89.765) >= 1.4705063220631649E-2);
+	}
 
-        assertEquals(Double.NaN, Math.IEEEremainder(Double.POSITIVE_INFINITY, 1.0));     
-        assertEquals(Double.NaN, Math.IEEEremainder(Double.NEGATIVE_INFINITY, 1.0));
-        assertEquals(1.0, Math.IEEEremainder(1.0, Double.POSITIVE_INFINITY));
-        assertEquals(1.0, Math.IEEEremainder(1.0, Double.NEGATIVE_INFINITY));
-        assertEquals(Double.NaN, Math.IEEEremainder(1.0, 0.0));
-        assertEquals(Double.NaN, Math.IEEEremainder(1.0, -0.0));        
-    }
-
-    /**
-     * @tests java.lang.Math#log(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "log",
-        args = {double.class}
-    )
-    public void test_logD() {
-        // Test for method double java.lang.Math.log(double)
-        for (double d = 10; d >= -10; d -= 0.5) {
-            double answer = Math.log(Math.exp(d));
-            assertTrue("Answer does not equal expected answer for d = " + d
-                    + " answer = " + answer, Math.abs(answer - d) <= Math
-                    .abs(d * 0.00000001));
-        }
-    }
+	/**
+	 * @tests java.lang.Math#log(double)
+	 */
+	public void test_logD() {
+		// Test for method double java.lang.Math.log(double)
+		for (double d = 10; d >= -10; d -= 0.5) {
+			double answer = Math.log(Math.exp(d));
+			assertTrue("Answer does not equal expected answer for d = " + d
+					+ " answer = " + answer, Math.abs(answer - d) <= Math
+					.abs(d * 0.00000001));
+		}
+	}
     
     /**
      * @tests java.lang.Math#log10(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "log10",
-        args = {double.class}
-    )
     @SuppressWarnings("boxing")
     public void test_log10_D() {
         // Test for special cases
@@ -581,12 +591,6 @@
     /**
      * @tests java.lang.Math#log1p(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "log1p",
-        args = {double.class}
-    )
     public void test_log1p_D() {
         // Test for special cases
         assertTrue("Should return NaN", Double.isNaN(Math.log1p(Double.NaN)));
@@ -594,11 +598,11 @@
         assertEquals("Should return POSITIVE_INFINITY",
                 Double.POSITIVE_INFINITY, Math.log1p(Double.POSITIVE_INFINITY), 0D);
         assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
-                .log1p(0.0)));
-        assertEquals(Double.doubleToLongBits(+0.0), Double
-                .doubleToLongBits(Math.log1p(+0.0)));
-        assertEquals(Double.doubleToLongBits(-0.0), Double
-                .doubleToLongBits(Math.log1p(-0.0)));
+				.log1p(0.0)));
+		assertEquals(Double.doubleToLongBits(+0.0), Double
+				.doubleToLongBits(Math.log1p(+0.0)));
+		assertEquals(Double.doubleToLongBits(-0.0), Double
+				.doubleToLongBits(Math.log1p(-0.0)));
 
         assertEquals("Should return -0.2941782295312541", -0.2941782295312541,
                 Math.log1p(-0.254856327), 0D);
@@ -612,323 +616,1032 @@
                 .log1p(Double.MIN_VALUE), 0D);
     }
 
-    /**
-     * @tests java.lang.Math#max(double, double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "max",
-        args = {double.class, double.class}
-    )
-    public void test_maxDD() {
-        // Test for method double java.lang.Math.max(double, double)
-        assertEquals("Incorrect double max value", 1908897.6000089, 
-                Math.max(-1908897.6000089,
-                1908897.6000089), 0D);
-        assertEquals("Incorrect double max value",
-                1908897.6000089, Math.max(2.0, 1908897.6000089), 0D);
-        assertEquals("Incorrect double max value", -2.0, Math.max(-2.0,
-                -1908897.6000089), 0D);
+	/**
+	 * @tests java.lang.Math#max(double, double)
+	 */
+	public void test_maxDD() {
+		// Test for method double java.lang.Math.max(double, double)
+		assertEquals("Incorrect double max value", 1908897.6000089, Math.max(-1908897.6000089,
+				1908897.6000089), 0D);
+		assertEquals("Incorrect double max value",
+				1908897.6000089, Math.max(2.0, 1908897.6000089), 0D);
+		assertEquals("Incorrect double max value", -2.0, Math.max(-2.0,
+				-1908897.6000089), 0D);
 
-        assertEquals("Incorrect returned value", Double.NaN, 
-                                                Math.max(-1.0, Double.NaN));
-        assertEquals("Incorrect returned value", Double.NaN, 
-                                                Math.max(Double.NaN, -1.0));
-        assertEquals("Incorrect returned value", 0, Math.max(0, -0), 0D);          
+		// Compare toString representations here since -0.0 = +0.0, and
+		// NaN != NaN and we need to distinguish
+        assertEquals("Max failed for NaN",
+                Double.toString(Double.NaN), Double.toString(Math.max(Double.NaN, 42.0d)));
+        assertEquals("Max failed for NaN",
+                Double.toString(Double.NaN), Double.toString(Math.max(42.0d, Double.NaN)));
+        assertEquals("Max failed for 0.0",
+                Double.toString(+0.0d), Double.toString(Math.max(+0.0d, -0.0d)));
+        assertEquals("Max failed for 0.0",
+                Double.toString(+0.0d), Double.toString(Math.max(-0.0d, +0.0d)));
+        assertEquals("Max failed for -0.0d",
+                Double.toString(-0.0d), Double.toString(Math.max(-0.0d, -0.0d)));
+        assertEquals("Max failed for 0.0",
+                Double.toString(+0.0d), Double.toString(Math.max(+0.0d, +0.0d)));
+	}
+
+	/**
+	 * @tests java.lang.Math#max(float, float)
+	 */
+	public void test_maxFF() {
+		// Test for method float java.lang.Math.max(float, float)
+		assertTrue("Incorrect float max value", Math.max(-1908897.600f,
+				1908897.600f) == 1908897.600f);
+		assertTrue("Incorrect float max value",
+				Math.max(2.0f, 1908897.600f) == 1908897.600f);
+		assertTrue("Incorrect float max value",
+				Math.max(-2.0f, -1908897.600f) == -2.0f);
+		
+	    // Compare toString representations here since -0.0 = +0.0, and
+        // NaN != NaN and we need to distinguish
+        assertEquals("Max failed for NaN",
+                Float.toString(Float.NaN), Float.toString(Math.max(Float.NaN, 42.0f)));
+        assertEquals("Max failed for NaN",
+                Float.toString(Float.NaN), Float.toString(Math.max(42.0f, Float.NaN)));
+        assertEquals("Max failed for 0.0",
+                Float.toString(+0.0f), Float.toString(Math.max(+0.0f, -0.0f)));
+        assertEquals("Max failed for 0.0",
+                Float.toString(+0.0f), Float.toString(Math.max(-0.0f, +0.0f)));
+        assertEquals("Max failed for -0.0f",
+                Float.toString(-0.0f), Float.toString(Math.max(-0.0f, -0.0f)));
+        assertEquals("Max failed for 0.0",
+                Float.toString(+0.0f), Float.toString(Math.max(+0.0f, +0.0f)));
+	}
+
+	/**
+	 * @tests java.lang.Math#max(int, int)
+	 */
+	public void test_maxII() {
+		// Test for method int java.lang.Math.max(int, int)
+		assertEquals("Incorrect int max value",
+				19088976, Math.max(-19088976, 19088976));
+		assertEquals("Incorrect int max value",
+				19088976, Math.max(20, 19088976));
+		assertEquals("Incorrect int max value", -20, Math.max(-20, -19088976));
+	}
+
+	/**
+	 * @tests java.lang.Math#max(long, long)
+	 */
+	public void test_maxJJ() {
+		// Test for method long java.lang.Math.max(long, long)
+		assertEquals("Incorrect long max value", 19088976000089L, Math.max(-19088976000089L,
+				19088976000089L));
+		assertEquals("Incorrect long max value",
+				19088976000089L, Math.max(20, 19088976000089L));
+		assertEquals("Incorrect long max value",
+				-20, Math.max(-20, -19088976000089L));
+	}
+
+	/**
+	 * @tests java.lang.Math#min(double, double)
+	 */
+	public void test_minDD() {
+		// Test for method double java.lang.Math.min(double, double)
+		assertEquals("Incorrect double min value", -1908897.6000089, Math.min(-1908897.6000089,
+				1908897.6000089), 0D);
+		assertEquals("Incorrect double min value",
+				2.0, Math.min(2.0, 1908897.6000089), 0D);
+		assertEquals("Incorrect double min value", -1908897.6000089, Math.min(-2.0,
+				-1908897.6000089), 0D);
+		assertEquals("Incorrect double min value", 1.0d, Math.min(1.0d, 1.0d));
+		
+	    // Compare toString representations here since -0.0 = +0.0, and
+        // NaN != NaN and we need to distinguish
+        assertEquals("Min failed for NaN",
+                Double.toString(Double.NaN), Double.toString(Math.min(Double.NaN, 42.0d)));
+        assertEquals("Min failed for NaN",
+                Double.toString(Double.NaN), Double.toString(Math.min(42.0d, Double.NaN)));
+        assertEquals("Min failed for -0.0",
+                Double.toString(-0.0d), Double.toString(Math.min(+0.0d, -0.0d)));
+        assertEquals("Min failed for -0.0",
+                Double.toString(-0.0d), Double.toString(Math.min(-0.0d, +0.0d)));
+        assertEquals("Min failed for -0.0d",
+                Double.toString(-0.0d), Double.toString(Math.min(-0.0d, -0.0d)));
+        assertEquals("Min failed for 0.0",
+                Double.toString(+0.0d), Double.toString(Math.min(+0.0d, +0.0d)));
+	}
+
+	/**
+	 * @tests java.lang.Math#min(float, float)
+	 */
+	public void test_minFF() {
+		// Test for method float java.lang.Math.min(float, float)
+		assertTrue("Incorrect float min value", Math.min(-1908897.600f,
+				1908897.600f) == -1908897.600f);
+		assertTrue("Incorrect float min value",
+				Math.min(2.0f, 1908897.600f) == 2.0f);
+		assertTrue("Incorrect float min value",
+				Math.min(-2.0f, -1908897.600f) == -1908897.600f);
+		assertEquals("Incorrect float min value", 1.0f, Math.min(1.0f, 1.0f));
+
+        // Compare toString representations here since -0.0 = +0.0, and
+        // NaN != NaN and we need to distinguish
+        assertEquals("Min failed for NaN",
+                Float.toString(Float.NaN), Float.toString(Math.min(Float.NaN, 42.0f)));
+        assertEquals("Min failed for NaN",
+                Float.toString(Float.NaN), Float.toString(Math.min(42.0f, Float.NaN)));
+        assertEquals("Min failed for -0.0",
+                Float.toString(-0.0f), Float.toString(Math.min(+0.0f, -0.0f)));
+        assertEquals("Min failed for -0.0",
+                Float.toString(-0.0f), Float.toString(Math.min(-0.0f, +0.0f)));
+        assertEquals("Min failed for -0.0f",
+                Float.toString(-0.0f), Float.toString(Math.min(-0.0f, -0.0f)));
+        assertEquals("Min failed for 0.0",
+                Float.toString(+0.0f), Float.toString(Math.min(+0.0f, +0.0f)));
+	}
+
+	/**
+	 * @tests java.lang.Math#min(int, int)
+	 */
+	public void test_minII() {
+		// Test for method int java.lang.Math.min(int, int)
+		assertEquals("Incorrect int min value",
+				-19088976, Math.min(-19088976, 19088976));
+		assertEquals("Incorrect int min value", 20, Math.min(20, 19088976));
+		assertEquals("Incorrect int min value",
+				-19088976, Math.min(-20, -19088976));
+
+	}
+
+	/**
+	 * @tests java.lang.Math#min(long, long)
+	 */
+	public void test_minJJ() {
+		// Test for method long java.lang.Math.min(long, long)
+		assertEquals("Incorrect long min value", -19088976000089L, Math.min(-19088976000089L,
+				19088976000089L));
+		assertEquals("Incorrect long min value",
+				20, Math.min(20, 19088976000089L));
+		assertEquals("Incorrect long min value",
+				-19088976000089L, Math.min(-20, -19088976000089L));
+	}
+	
+	/**
+     * start number cases for test_nextAfter_DD in MathTest/StrictMathTest
+     * NEXTAFTER_DD_START_CASES[i][0] is the start number
+     * NEXTAFTER_DD_START_CASES[i][1] is the nextUp of start number
+     * NEXTAFTER_DD_START_CASES[i][2] is the nextDown of start number
+     */
+    static final double NEXTAFTER_DD_START_CASES[][] = new double[][] {
+            { 3.4, 3.4000000000000004, 3.3999999999999995 },
+            { -3.4, -3.3999999999999995, -3.4000000000000004 },
+            { 3.4233E109, 3.4233000000000005E109, 3.4232999999999996E109 },
+            { -3.4233E109, -3.4232999999999996E109, -3.4233000000000005E109 },
+            { +0.0, Double.MIN_VALUE, -Double.MIN_VALUE },
+            { 0.0, Double.MIN_VALUE, -Double.MIN_VALUE },
+            { -0.0, Double.MIN_VALUE, -Double.MIN_VALUE },
+            { Double.MIN_VALUE, 1.0E-323, +0.0 },
+            { -Double.MIN_VALUE, -0.0, -1.0E-323 },
+            { Double.MIN_NORMAL, 2.225073858507202E-308, 2.225073858507201E-308 },
+            { -Double.MIN_NORMAL, -2.225073858507201E-308,
+                    -2.225073858507202E-308 },
+            { Double.MAX_VALUE, Double.POSITIVE_INFINITY,
+                    1.7976931348623155E308 },
+            { -Double.MAX_VALUE, -1.7976931348623155E308,
+                    Double.NEGATIVE_INFINITY },
+            { Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY,
+                    Double.MAX_VALUE },
+            { Double.NEGATIVE_INFINITY, -Double.MAX_VALUE,
+                    Double.NEGATIVE_INFINITY } };
+
+    /**
+     * direction number cases for test_nextAfter_DD/test_nextAfter_FD in
+     * MathTest/StrictMathTest
+     */
+    static final double NEXTAFTER_DD_FD_DIRECTION_CASES[] = new double[] {
+            Double.POSITIVE_INFINITY, Double.MAX_VALUE, 8.8, 3.4, 1.4,
+            Double.MIN_NORMAL, Double.MIN_NORMAL / 2, Double.MIN_VALUE, +0.0,
+            0.0, -0.0, -Double.MIN_VALUE, -Double.MIN_NORMAL / 2,
+            -Double.MIN_NORMAL, -1.4, -3.4, -8.8, -Double.MAX_VALUE,
+            Double.NEGATIVE_INFINITY };
+
+    /**
+     * @tests {@link java.lang.Math#nextAfter(double, double)}
+     * @since 1.6
+     */
+    @SuppressWarnings("boxing")
+    public void test_nextAfter_DD() {
+        // test for most cases without exception
+        for (int i = 0; i < NEXTAFTER_DD_START_CASES.length; i++) {
+            final double start = NEXTAFTER_DD_START_CASES[i][0];
+            final long nextUpBits = Double
+                    .doubleToLongBits(NEXTAFTER_DD_START_CASES[i][1]);
+            final long nextDownBits = Double
+                    .doubleToLongBits(NEXTAFTER_DD_START_CASES[i][2]);
+
+            for (int j = 0; j < NEXTAFTER_DD_FD_DIRECTION_CASES.length; j++) {
+                final double direction = NEXTAFTER_DD_FD_DIRECTION_CASES[j];
+                final long resultBits = Double.doubleToLongBits(Math.nextAfter(
+                        start, direction));
+                final long directionBits = Double.doubleToLongBits(direction);
+                if (direction > start) {
+                    assertEquals("Result should be next up-number.",
+                            nextUpBits, resultBits);
+                } else if (direction < start) {
+                    assertEquals("Result should be next down-number.",
+                            nextDownBits, resultBits);
+                } else {
+                    assertEquals("Result should be direction.", directionBits,
+                            resultBits);
+                }
+            }
+        }
+
+        // test for cases with NaN
+        for (int i = 0; i < NEXTAFTER_DD_START_CASES.length; i++) {
+            assertTrue("The result should be NaN.", Double.isNaN(Math
+                    .nextAfter(NEXTAFTER_DD_START_CASES[i][0], Double.NaN)));
+        }
+        for (int i = 0; i < NEXTAFTER_DD_FD_DIRECTION_CASES.length; i++) {
+            assertTrue("The result should be NaN.", Double.isNaN(Math
+                    .nextAfter(Double.NaN, NEXTAFTER_DD_FD_DIRECTION_CASES[i])));
+        }
+        assertTrue("The result should be NaN.", Double.isNaN(Math.nextAfter(
+                Double.NaN, Double.NaN)));
+
+        // test for exception
+        try {
+            Math.nextAfter((Double) null, 2.3);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            Math.nextAfter(2.3, (Double) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            Math.nextAfter((Double) null, (Double) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
     }
 
     /**
-     * @tests java.lang.Math#max(float, float)
+     * start number cases for test_nextAfter_FD in MathTest/StrictMathTest
+     * NEXTAFTER_FD_START_CASES[i][0] is the start number
+     * NEXTAFTER_FD_START_CASES[i][1] is the nextUp of start number
+     * NEXTAFTER_FD_START_CASES[i][2] is the nextDown of start number
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "max",
-        args = {float.class, float.class}
-    )
-    public void test_maxFF() {
-        // Test for method float java.lang.Math.max(float, float)
-        assertTrue("Incorrect float max value", Math.max(-1908897.600f,
-                1908897.600f) == 1908897.600f);
-        assertTrue("Incorrect float max value",
-                Math.max(2.0f, 1908897.600f) == 1908897.600f);
-        assertTrue("Incorrect float max value",
-                Math.max(-2.0f, -1908897.600f) == -2.0f);
-        assertEquals("Incorrect returned value", Float.NaN, 
-                Math.max(-1.0f, Float.NaN));
-        assertEquals("Incorrect returned value", Float.NaN, 
-                Math.max(Float.NaN, -1.0f));
-        assertEquals("Incorrect returned value", 0f, Math.max(0f, -0f));         
+    static final float NEXTAFTER_FD_START_CASES[][] = new float[][] {
+            { 3.4f, 3.4000003f, 3.3999999f },
+            { -3.4f, -3.3999999f, -3.4000003f },
+            { 3.4233E19f, 3.4233002E19f, 3.4232998E19f },
+            { -3.4233E19f, -3.4232998E19f, -3.4233002E19f },
+            { +0.0f, Float.MIN_VALUE, -Float.MIN_VALUE },
+            { 0.0f, Float.MIN_VALUE, -Float.MIN_VALUE },
+            { -0.0f, Float.MIN_VALUE, -Float.MIN_VALUE },
+            { Float.MIN_VALUE, 2.8E-45f, +0.0f },
+            { -Float.MIN_VALUE, -0.0f, -2.8E-45f },
+            { Float.MIN_NORMAL, 1.1754945E-38f, 1.1754942E-38f },
+            { -Float.MIN_NORMAL, -1.1754942E-38f, -1.1754945E-38f },
+            { Float.MAX_VALUE, Float.POSITIVE_INFINITY, 3.4028233E38f },
+            { -Float.MAX_VALUE, -3.4028233E38f, Float.NEGATIVE_INFINITY },
+            { Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.MAX_VALUE },
+            { Float.NEGATIVE_INFINITY, -Float.MAX_VALUE,
+                    Float.NEGATIVE_INFINITY } };
+
+    /**
+     * @tests {@link java.lang.Math#nextAfter(float, double)}
+     * @since 1.6
+     */
+    @SuppressWarnings("boxing")
+    public void test_nextAfter_FD() {
+        // test for most cases without exception
+        for (int i = 0; i < NEXTAFTER_FD_START_CASES.length; i++) {
+            final float start = NEXTAFTER_FD_START_CASES[i][0];
+            final int nextUpBits = Float
+                    .floatToIntBits(NEXTAFTER_FD_START_CASES[i][1]);
+            final int nextDownBits = Float
+                    .floatToIntBits(NEXTAFTER_FD_START_CASES[i][2]);
+
+            for (int j = 0; j < NEXTAFTER_DD_FD_DIRECTION_CASES.length; j++) {
+                final double direction = NEXTAFTER_DD_FD_DIRECTION_CASES[j];
+                final int resultBits = Float.floatToIntBits(Math.nextAfter(
+                        start, direction));
+                if (direction > start) {
+                    assertEquals("Result should be next up-number.",
+                            nextUpBits, resultBits);
+                } else if (direction < start) {
+                    assertEquals("Result should be next down-number.",
+                            nextDownBits, resultBits);
+                } else {
+                    final int equivalentBits = Float.floatToIntBits(new Float(
+                            direction));
+                    assertEquals(
+                            "Result should be a number equivalent to direction.",
+                            equivalentBits, resultBits);
+                }
+            }
+        }
+
+        // test for cases with NaN
+        for (int i = 0; i < NEXTAFTER_FD_START_CASES.length; i++) {
+            assertTrue("The result should be NaN.", Float.isNaN(Math.nextAfter(
+                    NEXTAFTER_FD_START_CASES[i][0], Float.NaN)));
+        }
+        for (int i = 0; i < NEXTAFTER_DD_FD_DIRECTION_CASES.length; i++) {
+            assertTrue("The result should be NaN.", Float.isNaN(Math.nextAfter(
+                    Float.NaN, NEXTAFTER_DD_FD_DIRECTION_CASES[i])));
+        }
+        assertTrue("The result should be NaN.", Float.isNaN(Math.nextAfter(
+                Float.NaN, Float.NaN)));
+
+        // test for exception
+        try {
+            Math.nextAfter((Float) null, 2.3);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            Math.nextAfter(2.3, (Float) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            Math.nextAfter((Float) null, (Float) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
     }
 
     /**
-     * @tests java.lang.Math#max(int, int)
+     * @tests {@link java.lang.Math#nextUp(double)}
+     * @since 1.6
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "max",
-        args = {int.class, int.class}
-    )    
-    public void test_maxII() {
-        // Test for method int java.lang.Math.max(int, int)
-        assertEquals("Incorrect int max value",
-                19088976, Math.max(-19088976, 19088976));
-        assertEquals("Incorrect int max value",
-                19088976, Math.max(20, 19088976));
-        assertEquals("Incorrect int max value", -20, Math.max(-20, -19088976));
+    @SuppressWarnings("boxing")
+    public void test_nextUp_D() {
+        // This method is semantically equivalent to nextAfter(d,
+        // Double.POSITIVE_INFINITY),
+        // so we use the data of test_nextAfter_DD
+        for (int i = 0; i < NEXTAFTER_DD_START_CASES.length; i++) {
+            final double start = NEXTAFTER_DD_START_CASES[i][0];
+            final long nextUpBits = Double
+                    .doubleToLongBits(NEXTAFTER_DD_START_CASES[i][1]);
+            final long resultBits = Double.doubleToLongBits(Math.nextUp(start));
+            assertEquals("Result should be next up-number.", nextUpBits,
+                    resultBits);
+        }
+
+        // test for cases with NaN
+        assertTrue("The result should be NaN.", Double.isNaN(Math
+                .nextUp(Double.NaN)));
+
+        // test for exception
+        try {
+            Math.nextUp((Double) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
     }
 
     /**
-     * @tests java.lang.Math#max(long, long)
+     * @tests {@link java.lang.Math#nextUp(float)}
+     * @since 1.6
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "max",
-        args = {long.class, long.class}
-    )        
-    public void test_maxJJ() {
-        // Test for method long java.lang.Math.max(long, long)
-        assertEquals("Incorrect long max value", 19088976000089L, Math.max(-19088976000089L,
-                19088976000089L));
-        assertEquals("Incorrect long max value",
-                19088976000089L, Math.max(20, 19088976000089L));
-        assertEquals("Incorrect long max value",
-                -20, Math.max(-20, -19088976000089L));
+    @SuppressWarnings("boxing")
+    public void test_nextUp_F() {
+        // This method is semantically equivalent to nextAfter(f,
+        // Float.POSITIVE_INFINITY),
+        // so we use the data of test_nextAfter_FD
+        for (int i = 0; i < NEXTAFTER_FD_START_CASES.length; i++) {
+            final float start = NEXTAFTER_FD_START_CASES[i][0];
+            final int nextUpBits = Float
+                    .floatToIntBits(NEXTAFTER_FD_START_CASES[i][1]);
+            final int resultBits = Float.floatToIntBits(Math.nextUp(start));
+            assertEquals("Result should be next up-number.", nextUpBits,
+                    resultBits);
+        }
+
+        // test for cases with NaN
+        assertTrue("The result should be NaN.", Float.isNaN(Math
+                .nextUp(Float.NaN)));
+
+        // test for exception
+        try {
+            Math.nextUp((Float) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
     }
 
-    /**
-     * @tests java.lang.Math#min(double, double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "min",
-        args = {double.class, double.class}
-    )
-    public void test_minDD() {
-        // Test for method double java.lang.Math.min(double, double)
-        assertEquals("Incorrect double min value", -1908897.6000089, Math.min(-1908897.6000089,
-                1908897.6000089), 0D);
-        assertEquals("Incorrect double min value",
-                2.0, Math.min(2.0, 1908897.6000089), 0D);
-        assertEquals("Incorrect double min value", -1908897.6000089, Math.min(-2.0,
-                -1908897.6000089), 0D);
-        assertEquals("Incorrect returned value", Double.NaN, 
-                Math.min(-1.0, Double.NaN));
-        assertEquals("Incorrect returned value", Double.NaN, 
-                Math.min(Double.NaN, -1.0));
-        assertEquals("Incorrect returned value", -0.0, Math.min(0.0, -0.0));        
-    }
+	/**
+	 * @tests java.lang.Math#pow(double, double)
+	 */
+	public void test_powDD() {
+		// Test for method double java.lang.Math.pow(double, double)
+        double NZERO = longTodouble(doubleTolong(0.0) ^ 0x8000000000000000L);
+        double p1 = 1.0;
+        double p2 = 2.0;
+        double p3 = 3.0;
+        double p4 = 4.0;
+        double p5 = 5.0;
+        double p6 = 6.0;
+        double p7 = 7.0;
+        double p8 = 8.0;
+        double p9 = 9.0;
+        double p10 = 10.0;
+        double p11 = 11.0;
+        double p12 = 12.0;
+        double p13 = 13.0;
+        double p14 = 14.0;
+        double p15 = 15.0;
+        double p16 = 16.0;
+        double[] values = { p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12,
+                p13, p14, p15, p16 };
 
-    /**
-     * @tests java.lang.Math#min(float, float)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "min",
-        args = {float.class, float.class}
-    )
-    public void test_minFF() {
-        // Test for method float java.lang.Math.min(float, float)
-        assertTrue("Incorrect float min value", Math.min(-1908897.600f,
-                1908897.600f) == -1908897.600f);
-        assertTrue("Incorrect float min value",
-                Math.min(2.0f, 1908897.600f) == 2.0f);
-        assertTrue("Incorrect float min value",
-                Math.min(-2.0f, -1908897.600f) == -1908897.600f);
-        assertEquals("Incorrect returned value", Float.NaN, 
-                Math.min(-1.0f, Float.NaN));
-        assertEquals("Incorrect returned value", Float.NaN, 
-                Math.min(Float.NaN, -1.0f));
-        assertEquals("Incorrect returned value", -0f, Math.min(0f, -0f));        
-    }
+        for (int x = 0; x < values.length; x++) {
+            double dval = values[x];
+            double nagateDval = negateDouble(dval);
+            if (nagateDval == Double.NaN) {
+                continue;
+            }
 
-    /**
-     * @tests java.lang.Math#min(int, int)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "min",
-        args = {int.class, int.class}
-    )
-    public void test_minII() {
-        // Test for method int java.lang.Math.min(int, int)
-        assertEquals("Incorrect int min value",
-                -19088976, Math.min(-19088976, 19088976));
-        assertEquals("Incorrect int min value", 20, Math.min(20, 19088976));
-        assertEquals("Incorrect int min value",
-                -19088976, Math.min(-20, -19088976));
+            // If the second argument is positive or negative zero, then the
+            // result is 1.0.
+            assertEquals("Result should be Math.pow(" + dval
+                    + ",-0.0)=+1.0", 1.0, Math.pow(dval, NZERO));
+            assertEquals("Result should be Math.pow(" + nagateDval
+                    + ",-0.0)=+1.0", 1.0, Math.pow(nagateDval, NZERO));
+            assertEquals("Result should be Math.pow(" + dval
+                    + ",+0.0)=+1.0", 1.0, Math.pow(dval, +0.0));
+            assertEquals("Result should be Math.pow(" + nagateDval
+                    + ",+0.0)=+1.0", 1.0, Math.pow(nagateDval, +0.0));
 
-    }
+            // If the second argument is 1.0, then the result is the same as the
+            // first argument.
+            assertEquals("Result should be Math.pow(" + dval + "," + 1.0 + ")="
+                    + dval, dval, Math.pow(dval, 1.0));
+            assertEquals("Result should be Math.pow(" + nagateDval + "," + 1.0
+                    + ")=" + nagateDval, nagateDval, Math.pow(nagateDval, 1.0));
 
-    /**
-     * @tests java.lang.Math#min(long, long)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "min",
-        args = {long.class, long.class}
-    )
-    public void test_minJJ() {
-        // Test for method long java.lang.Math.min(long, long)
-        assertEquals("Incorrect long min value", -19088976000089L, Math.min(-19088976000089L,
-                19088976000089L));
-        assertEquals("Incorrect long min value",
-                20, Math.min(20, 19088976000089L));
-        assertEquals("Incorrect long min value",
-                -19088976000089L, Math.min(-20, -19088976000089L));
-    }
+            // If the second argument is NaN, then the result is NaN.
+            assertEquals("Result should be Math.pow(" + dval + "," + Double.NaN
+                    + ")=" + Double.NaN,  Double.NaN, Math.pow(dval, Double.NaN));
+            assertEquals("Result should be Math.pow(" + nagateDval + ","
+                    + Double.NaN + ")=" + Double.NaN,  Double.NaN, Math.pow(nagateDval,
+                    Double.NaN));
 
-    /**
-     * @tests java.lang.Math#pow(double, double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "pow",
-        args = {double.class, double.class}
-    )
-    public void test_powDD() {
-        // Test for method double java.lang.Math.pow(double, double)
-        assertTrue("pow returned incorrect value",
-                (long) Math.pow(2, 8) == 256l);
-        assertTrue("pow returned incorrect value",
-                Math.pow(2, -8) == 0.00390625d);
-        assertEquals("Incorrect root returned1",
+            if (dval > 1) {
+                // If the first argument is NaN and the second argument is
+                // nonzero,
+                // then the result is NaN.
+                assertEquals("Result should be Math.pow(" + Double.NaN + ","
+                        + dval + ")=" + Double.NaN,  Double.NaN, Math.pow(Double.NaN, dval));
+                assertEquals("Result should be Math.pow(" + Double.NaN + ","
+                        + nagateDval + ")=" + Double.NaN,  Double.NaN, Math.pow(Double.NaN,
+                        nagateDval));
+
+                /*
+                 * If the first argument is positive zero and the second
+                 * argument is greater than zero, or the first argument is
+                 * positive infinity and the second argument is less than zero,
+                 * then the result is positive zero.
+                 */
+                assertEquals("Result should be Math.pow(" + 0.0 + "," + dval
+                        + ")=" + 0.0, +0.0, Math.pow(0.0, dval));
+                assertEquals("Result should be Math.pow("
+                        + Double.POSITIVE_INFINITY + "," + nagateDval + ")="
+                        + 0.0, +0.0, Math.pow(Double.POSITIVE_INFINITY, nagateDval));
+
+                /*
+                 * If the first argument is positive zero and the second
+                 * argument is less than zero, or the first argument is positive
+                 * infinity and the second argument is greater than zero, then
+                 * the result is positive infinity.
+                 */
+                assertEquals("Result should be Math.pow(" + 0.0 + ","
+                        + nagateDval + ")=" + Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
+                        Math.pow(0.0, nagateDval));
+                assertEquals("Result should be Math.pow("
+                        + Double.POSITIVE_INFINITY + "," + dval + ")="
+                        + Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Math.pow(
+                        Double.POSITIVE_INFINITY, dval));
+
+                // Not a finite odd integer
+                if (dval % 2 == 0) {
+                    /*
+                     * If the first argument is negative zero and the second
+                     * argument is greater than zero but not a finite odd
+                     * integer, or the first argument is negative infinity and
+                     * the second argument is less than zero but not a finite
+                     * odd integer, then the result is positive zero.
+                     */
+                    assertEquals("Result should be Math.pow(" + NZERO + ","
+                            + dval + ")=" + 0.0, +0.0, Math.pow(NZERO, dval));
+                    assertEquals("Result should be Math.pow("
+                            + Double.NEGATIVE_INFINITY + "," + nagateDval
+                            + ")=" + 0.0, +0.0, Math.pow(Double.NEGATIVE_INFINITY,
+                            nagateDval));
+
+                    /*
+                     * If the first argument is negative zero and the second
+                     * argument is less than zero but not a finite odd integer,
+                     * or the first argument is negative infinity and the second
+                     * argument is greater than zero but not a finite odd
+                     * integer, then the result is positive infinity.
+                     */
+                    assertEquals("Result should be Math.pow(" + NZERO + ","
+                            + nagateDval + ")=" + Double.POSITIVE_INFINITY,Double.POSITIVE_INFINITY,
+                            Math.pow(NZERO, nagateDval));
+                    assertEquals("Result should be Math.pow("
+                            + Double.NEGATIVE_INFINITY + "," + dval + ")="
+                            + Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Math.pow(
+                            Double.NEGATIVE_INFINITY, dval));
+                }
+
+                // finite odd integer
+                if (dval % 2 != 0) {
+                    /*
+                     * If the first argument is negative zero and the second
+                     * argument is a positive finite odd integer, or the first
+                     * argument is negative infinity and the second argument is
+                     * a negative finite odd integer, then the result is
+                     * negative zero.
+                     */
+                    assertEquals("Result should be Math.pow(" + NZERO + ","
+                            + dval + ")=" + NZERO, NZERO, Math.pow(NZERO, dval));
+                    assertEquals("Result should be Math.pow("
+                            + Double.NEGATIVE_INFINITY + "," + nagateDval
+                            + ")=" + NZERO, NZERO, Math.pow(Double.NEGATIVE_INFINITY,
+                            nagateDval));
+                    /*
+                     * If the first argument is negative zero and the second
+                     * argument is a negative finite odd integer, or the first
+                     * argument is negative infinity and the second argument is
+                     * a positive finite odd integer then the result is negative
+                     * infinity.
+                     */
+                    assertEquals("Result should be Math.pow(" + NZERO + ","
+                            + nagateDval + ")=" + Double.NEGATIVE_INFINITY,Double.NEGATIVE_INFINITY,
+                            Math.pow(NZERO, nagateDval));
+                    assertEquals("Result should be Math.pow("
+                            + Double.NEGATIVE_INFINITY + "," + dval + ")="
+                            + Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Math.pow(
+                            Double.NEGATIVE_INFINITY, dval));
+                }
+
+                /**
+                 * 1. If the first argument is finite and less than zero if the
+                 * second argument is a finite even integer, the result is equal
+                 * to the result of raising the absolute value of the first
+                 * argument to the power of the second argument 
+                 * 
+                 * 2. if the second argument is a finite odd integer, the result is equal to the
+                 * negative of the result of raising the absolute value of the
+                 * first argument to the power of the second argument 
+                 * 
+                 * 3. if the second argument is finite and not an integer, then the result
+                 * is NaN.
+                 */
+                for (int j = 1; j < values.length; j++) {
+                    double jval = values[j];
+                    if (jval % 2.0 == 0.0) {
+                        assertEquals("" + nagateDval + " " + jval, Math.pow(
+                                dval, jval), Math.pow(nagateDval, jval));
+                    } else {
+                        assertEquals("" + nagateDval + " " + jval, -1.0
+                                * Math.pow(dval, jval), Math.pow(nagateDval,
+                                jval));
+                    }
+                    assertEquals(Double.NaN, Math
+                            .pow(nagateDval, jval / 0.5467));
+                    assertEquals(Double.NaN, Math.pow(nagateDval, -1.0 * jval
+                            / 0.5467));
+                }
+            }
+
+            // If the absolute value of the first argument equals 1 and the
+            // second argument is infinite, then the result is NaN.
+            if (dval == 1) {
+                assertEquals("Result should be Math.pow(" + dval + ","
+                        + Double.POSITIVE_INFINITY + ")=" + Double.NaN, Double.NaN, Math
+                        .pow(dval, Double.POSITIVE_INFINITY));
+                assertEquals("Result should be Math.pow(" + dval + ","
+                        + Double.NEGATIVE_INFINITY + ")=" + Double.NaN, Double.NaN, Math
+                        .pow(dval, Double.NEGATIVE_INFINITY));
+
+                assertEquals("Result should be Math.pow(" + nagateDval + ","
+                        + Double.POSITIVE_INFINITY + ")=" + Double.NaN, Double.NaN, Math
+                        .pow(nagateDval, Double.POSITIVE_INFINITY));
+                assertEquals("Result should be Math.pow(" + nagateDval + ","
+                        + Double.NEGATIVE_INFINITY + ")=" + Double.NaN, Double.NaN, Math
+                        .pow(nagateDval, Double.NEGATIVE_INFINITY));
+            }
+
+            if (dval > 1) {
+                /*
+                 * If the absolute value of the first argument is greater than 1
+                 * and the second argument is positive infinity, or the absolute
+                 * value of the first argument is less than 1 and the second
+                 * argument is negative infinity, then the result is positive
+                 * infinity.
+                 */
+                assertEquals("Result should be Math.pow(" + dval + ","
+                        + Double.POSITIVE_INFINITY + ")="
+                        + Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Math.pow(dval,
+                        Double.POSITIVE_INFINITY));
+
+                assertEquals("Result should be Math.pow(" + nagateDval + ","
+                        + Double.NEGATIVE_INFINITY + ")="
+                        + Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Math.pow(-0.13456,
+                        Double.NEGATIVE_INFINITY));
+
+                /*
+                 * If the absolute value of the first argument is greater than 1
+                 * and the second argument is negative infinity, or the absolute
+                 * value of the first argument is less than 1 and the second
+                 * argument is positive infinity, then the result is positive
+                 * zero.
+                 */
+                assertEquals("Result should be Math.pow(" + dval + ","
+                        + Double.NEGATIVE_INFINITY + ")= +0.0", +0.0, Math.pow(dval,
+                        Double.NEGATIVE_INFINITY));
+                assertEquals("Result should be Math.pow(" + nagateDval + ","
+                        + Double.POSITIVE_INFINITY + ")= +0.0", +0.0, Math.pow(
+                        -0.13456, Double.POSITIVE_INFINITY));
+            }
+
+            assertEquals("Result should be Math.pow(" + 0.0 + "," + dval + ")="
+                    + 0.0, 0.0, Math.pow(0.0, dval));
+            assertEquals("Result should be Math.pow(" + Double.NaN + "," + dval
+                    + ")=" + Double.NaN, Double.NaN, Math.pow(Double.NaN, dval));
+        }
+		assertTrue("pow returned incorrect value",
+				(long) Math.pow(2, 8) == 256l);
+		assertTrue("pow returned incorrect value",
+				Math.pow(2, -8) == 0.00390625d);
+		assertEquals("Incorrect root returned1",
                              2, Math.sqrt(Math.pow(Math.sqrt(2), 4)), 0);
-        
-        assertEquals("pow returned incorrect value", 1.0, Math.pow(1, 0));
-        assertEquals("pow returned incorrect value", 2.0, Math.pow(2, 1));
-        assertEquals("pow returned incorrect value", Double.NaN, 
-                                        Math.pow(Double.MAX_VALUE, Double.NaN)); 
-        assertEquals("pow returned incorrect value", Double.NaN, 
-                                        Math.pow(Double.NaN, Double.MAX_VALUE));        
-        assertEquals("pow returned incorrect value", Double.POSITIVE_INFINITY, 
-                                       Math.pow(1.1, Double.POSITIVE_INFINITY));      
-        assertEquals("pow returned incorrect value", Double.POSITIVE_INFINITY, 
-                                       Math.pow(0.9, Double.NEGATIVE_INFINITY));   
-        
-        assertEquals("pow returned incorrect value", 0.0, 
-                                       Math.pow(1.1, Double.NEGATIVE_INFINITY));
-        assertEquals("pow returned incorrect value", 0.0, 
-                                       Math.pow(0.9, Double.POSITIVE_INFINITY));   
-        
-        assertEquals("pow returned incorrect value", Double.NaN, 
-                                       Math.pow(1.0, Double.NEGATIVE_INFINITY));
-        assertEquals("pow returned incorrect value", Double.NaN, 
-                                       Math.pow(1.0, Double.POSITIVE_INFINITY)); 
 
-        assertEquals("pow returned incorrect value", 0.0, Math.pow(0, 1));
-        assertEquals("pow returned incorrect value", 0.0, 
-                                      Math.pow(Double.POSITIVE_INFINITY, -0.1));
+		assertEquals(Double.NEGATIVE_INFINITY, Math.pow(-10.0, 3.093403029238847E15));
+		assertEquals(Double.POSITIVE_INFINITY, Math.pow(10.0, 3.093403029238847E15));
+	}
+
+    private double longTodouble(long longvalue) {
+        return Double.longBitsToDouble(longvalue);
+    }
+
+    private long doubleTolong(double doublevalue) {
+        return Double.doubleToLongBits(doublevalue);
+    }
+
+    private double negateDouble(double doublevalue) {
+        return doublevalue * -1.0;
+    }
+
+	/**
+	 * @tests java.lang.Math#rint(double)
+	 */
+	public void test_rintD() {
+		// Test for method double java.lang.Math.rint(double)
+		assertEquals("Failed to round properly - up to odd",
+				3.0, Math.rint(2.9), 0D);
+		assertTrue("Failed to round properly - NaN", Double.isNaN(Math
+				.rint(Double.NaN)));
+		assertEquals("Failed to round properly down  to even",
+				2.0, Math.rint(2.1), 0D);
+		assertTrue("Failed to round properly " + 2.5 + " to even", Math
+				.rint(2.5) == 2.0);
+                assertTrue("Failed to round properly " + (+0.0d),
+                        Math.rint(+0.0d) == +0.0d);
+                assertTrue("Failed to round properly " + (-0.0d),
+                        Math.rint(-0.0d) == -0.0d);
+	}
+
+	/**
+	 * @tests java.lang.Math#round(double)
+	 */
+	public void test_roundD() {
+		// Test for method long java.lang.Math.round(double)
+		assertEquals("Incorrect rounding of a float", -91, Math.round(-90.89d));
+	}
+
+	/**
+	 * @tests java.lang.Math#round(float)
+	 */
+	public void test_roundF() {
+		// Test for method int java.lang.Math.round(float)
+		assertEquals("Incorrect rounding of a float", -91, Math.round(-90.89f));
+	}
+	
+	/**
+     * @tests {@link java.lang.Math#scalb(double, int)}
+     * @since 1.6
+     */
+    @SuppressWarnings("boxing")
+    public void test_scalb_DI() {
+        // result is normal
+        assertEquals(4.1422946304E7, Math.scalb(1.2345, 25));
+        assertEquals(3.679096698760986E-8, Math.scalb(1.2345, -25));
+        assertEquals(1.2345, Math.scalb(1.2345, 0));
+        assertEquals(7868514.304, Math.scalb(0.2345, 25));
+
+        double normal = Math.scalb(0.2345, -25);
+        assertEquals(6.98864459991455E-9, normal);
+        // precision kept
+        assertEquals(0.2345, Math.scalb(normal, 25));
+
+        assertEquals(0.2345, Math.scalb(0.2345, 0));
+        assertEquals(-4.1422946304E7, Math.scalb(-1.2345, 25));
+        assertEquals(-6.98864459991455E-9, Math.scalb(-0.2345, -25));
+        assertEquals(2.0, Math.scalb(Double.MIN_NORMAL / 2, 1024));
+        assertEquals(64.0, Math.scalb(Double.MIN_VALUE, 1080));
+        assertEquals(234, Math.getExponent(Math.scalb(1.0, 234)));
+        assertEquals(3.9999999999999996, Math.scalb(Double.MAX_VALUE,
+                Double.MIN_EXPONENT));
+
+        // result is near infinity
+        double halfMax = Math.scalb(1.0, Double.MAX_EXPONENT);
+        assertEquals(8.98846567431158E307, halfMax);
+        assertEquals(Double.MAX_VALUE, halfMax - Math.ulp(halfMax) + halfMax);
+        assertEquals(Double.POSITIVE_INFINITY, halfMax + halfMax);
+        assertEquals(1.7976931348623155E308, Math.scalb(1.0 - Math.ulp(1.0),
+                Double.MAX_EXPONENT + 1));
+        assertEquals(Double.POSITIVE_INFINITY, Math.scalb(1.0 - Math.ulp(1.0),
+                Double.MAX_EXPONENT + 2));
+
+        halfMax = Math.scalb(-1.0, Double.MAX_EXPONENT);
+        assertEquals(-8.98846567431158E307, halfMax);
+        assertEquals(-Double.MAX_VALUE, halfMax + Math.ulp(halfMax) + halfMax);
+        assertEquals(Double.NEGATIVE_INFINITY, halfMax + halfMax);
+
+        assertEquals(Double.POSITIVE_INFINITY, Math.scalb(0.345, 1234));
+        assertEquals(Double.POSITIVE_INFINITY, Math.scalb(44.345E102, 934));
+        assertEquals(Double.NEGATIVE_INFINITY, Math.scalb(-44.345E102, 934));
+
+        assertEquals(Double.POSITIVE_INFINITY, Math.scalb(
+                Double.MIN_NORMAL / 2, 4000));
+        assertEquals(Double.POSITIVE_INFINITY, Math.scalb(Double.MIN_VALUE,
+                8000));
+        assertEquals(Double.POSITIVE_INFINITY, Math.scalb(Double.MAX_VALUE, 1));
+        assertEquals(Double.POSITIVE_INFINITY, Math.scalb(
+                Double.POSITIVE_INFINITY, 0));
+        assertEquals(Double.POSITIVE_INFINITY, Math.scalb(
+                Double.POSITIVE_INFINITY, -1));
+        assertEquals(Double.NEGATIVE_INFINITY, Math.scalb(
+                Double.NEGATIVE_INFINITY, -1));
+        assertEquals(Double.NEGATIVE_INFINITY, Math.scalb(
+                Double.NEGATIVE_INFINITY, Double.MIN_EXPONENT));
+
+        // result is subnormal/zero
+        long posZeroBits = Double.doubleToLongBits(+0.0);
+        long negZeroBits = Double.doubleToLongBits(-0.0);
+        assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(+0.0,
+                Integer.MAX_VALUE)));
+        assertEquals(posZeroBits, Double.doubleToLongBits(Math
+                .scalb(+0.0, -123)));
+        assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(+0.0, 0)));
+        assertEquals(negZeroBits, Double
+                .doubleToLongBits(Math.scalb(-0.0, 123)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(-0.0,
+                Integer.MIN_VALUE)));
+
+        assertEquals(Double.MIN_VALUE, Math.scalb(1.0, -1074));
+        assertEquals(posZeroBits, Double.doubleToLongBits(Math
+                .scalb(1.0, -1075)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(-1.0,
+                -1075)));
+
+        // precision lost
+        assertEquals(Math.scalb(21.405, -1078), Math.scalb(21.405, -1079));
+        assertEquals(Double.MIN_VALUE, Math.scalb(21.405, -1079));
+        assertEquals(-Double.MIN_VALUE, Math.scalb(-21.405, -1079));
+        assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(21.405,
+                -1080)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(-21.405,
+                -1080)));
+        assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(
+                Double.MIN_VALUE, -1)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(
+                -Double.MIN_VALUE, -1)));
+        assertEquals(Double.MIN_VALUE, Math.scalb(Double.MIN_NORMAL, -52));
+        assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(
+                Double.MIN_NORMAL, -53)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(
+                -Double.MIN_NORMAL, -53)));
+        assertEquals(Double.MIN_VALUE, Math.scalb(Double.MAX_VALUE, -2098));
+        assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(
+                Double.MAX_VALUE, -2099)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(
+                -Double.MAX_VALUE, -2099)));
+        assertEquals(Double.MIN_VALUE, Math.scalb(Double.MIN_NORMAL / 3, -51));
+        assertEquals(posZeroBits, Double.doubleToLongBits(Math.scalb(
+                Double.MIN_NORMAL / 3, -52)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(Math.scalb(
+                -Double.MIN_NORMAL / 3, -52)));
+        double subnormal = Math.scalb(Double.MIN_NORMAL / 3, -25);
+        assertEquals(2.2104123E-316, subnormal);
+        // precision lost
+        assertFalse(Double.MIN_NORMAL / 3 == Math.scalb(subnormal, 25));
+
+        // NaN
+        assertTrue(Double.isNaN(Math.scalb(Double.NaN, 1)));
+        assertTrue(Double.isNaN(Math.scalb(Double.NaN, 0)));
+        assertTrue(Double.isNaN(Math.scalb(Double.NaN, -120)));
+
+        assertEquals(1283457024, Double.doubleToLongBits(Math.scalb(
+                Double.MIN_VALUE * 153, 23)));
+        assertEquals(-9223372035571318784L, Double.doubleToLongBits(Math.scalb(
+                -Double.MIN_VALUE * 153, 23)));
+        assertEquals(36908406321184768L, Double.doubleToLongBits(Math.scalb(
+                Double.MIN_VALUE * 153, 52)));
+        assertEquals(-9186463630533591040L, Double.doubleToLongBits(Math.scalb(
+                -Double.MIN_VALUE * 153, 52)));
+
+        // test for exception
+        try {
+            Math.scalb((Double) null, (Integer) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            Math.scalb(1.0, (Integer) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            Math.scalb((Double) null, 1);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
         
-        assertEquals("pow returned incorrect value", Double.POSITIVE_INFINITY, 
-                                                               Math.pow(0, -1));
-        assertEquals("pow returned incorrect value", Double.POSITIVE_INFINITY, 
-                                         Math.pow(Double.POSITIVE_INFINITY, 1));
-        
-        assertEquals("pow returned incorrect value", 0.0, 
-                                                           Math.pow(-0.0, 0.9));
-        assertEquals("pow returned incorrect value", 0.0, 
-                                      Math.pow(Double.NEGATIVE_INFINITY, -0.9));
-        
-        assertEquals("pow returned incorrect value", -0.0, 
-                                                             Math.pow(-0.0, 1));
-        assertEquals("pow returned incorrect value", -0.0, 
-                                        Math.pow(Double.NEGATIVE_INFINITY, -1));  
-        
-        assertEquals("pow returned incorrect value", Double.POSITIVE_INFINITY, 
-                                                          Math.pow(-0.0, -0.9));
-        assertEquals("pow returned incorrect value", Double.POSITIVE_INFINITY, 
-                                       Math.pow(Double.NEGATIVE_INFINITY, 0.9));  
-        
-        assertEquals("pow returned incorrect value", Double.NEGATIVE_INFINITY, 
-                                                            Math.pow(-0.0, -1));
-        assertEquals("pow returned incorrect value", Double.NEGATIVE_INFINITY, 
-                                         Math.pow(Double.NEGATIVE_INFINITY, 1));   
-        
-        assertEquals("pow returned incorrect value", 0.81, Math.pow(-0.9, 2));  
-        assertEquals("pow returned incorrect value", -0.9, Math.pow(-0.9, 1)); 
-        assertEquals("pow returned incorrect value", Double.NaN, 
-                                                           Math.pow(-0.9, 0.1));
+        long b1em1022 = 0x0010000000000000L; // bit representation of
+                                                // Double.MIN_NORMAL
+        long b1em1023 = 0x0008000000000000L; // bit representation of half of
+                                                // Double.MIN_NORMAL
+        // assert exact identity
+        assertEquals(b1em1023, Double.doubleToLongBits(Math.scalb(Double
+                .longBitsToDouble(b1em1022), -1)));
     }
 
     /**
-     * @tests java.lang.Math#rint(double)
+     * @tests {@link java.lang.Math#scalb(float, int)}
+     * @since 1.6
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "rint",
-        args = {double.class}
-    )
-    public void test_rintD() {
-        // Test for method double java.lang.Math.rint(double)
-        assertEquals("Failed to round properly - up to odd",
-                3.0, Math.rint(2.9), 0D);
-        assertTrue("Failed to round properly - NaN", Double.isNaN(Math
-                .rint(Double.NaN)));
-        assertEquals("Failed to round properly down  to even",
-                2.0, Math.rint(2.1), 0D);
-        assertTrue("Failed to round properly " + 2.5 + " to even", Math
-                .rint(2.5) == 2.0);
-    }
+    @SuppressWarnings("boxing")
+    public void test_scalb_FI() {
+        // result is normal
+        assertEquals(4.1422946304E7f, Math.scalb(1.2345f, 25));
+        assertEquals(3.679096698760986E-8f, Math.scalb(1.2345f, -25));
+        assertEquals(1.2345f, Math.scalb(1.2345f, 0));
+        assertEquals(7868514.304f, Math.scalb(0.2345f, 25));
 
-    /**
-     * @tests java.lang.Math#round(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "round",
-        args = {double.class}
-    )
-    public void test_roundD() {
-        // Test for method long java.lang.Math.round(double)
-        assertEquals("Incorrect rounding of a float", -91, Math.round(-90.89d));
-        assertEquals("Incorrect rounding of a float", 0, 
-                                                        Math.round(Double.NaN));
-        assertEquals("Incorrect rounding of a float", Long.MIN_VALUE, 
-                                          Math.round(Double.NEGATIVE_INFINITY));
-        assertEquals("Incorrect rounding of a float", Long.MAX_VALUE, 
-                                          Math.round(Double.POSITIVE_INFINITY));        
-    }
+        float normal = Math.scalb(0.2345f, -25);
+        assertEquals(6.98864459991455E-9f, normal);
+        // precision kept
+        assertEquals(0.2345f, Math.scalb(normal, 25));
 
-    /**
-     * @tests java.lang.Math#round(float)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "round",
-        args = {float.class}
-    )
-    public void test_roundF() {
-        // Test for method int java.lang.Math.round(float)
-        assertEquals("Incorrect rounding of a float", -91, Math.round(-90.89f));
-        assertEquals("Incorrect rounding of a float", 0, 
-                                                        Math.round(Float.NaN));
-        assertEquals("Incorrect rounding of a float", Integer.MIN_VALUE, 
-                                          Math.round(Float.NEGATIVE_INFINITY));
-        assertEquals("Incorrect rounding of a float", Integer.MAX_VALUE, 
-                                          Math.round(Float.POSITIVE_INFINITY));          
+        assertEquals(0.2345f, Math.scalb(0.2345f, 0));
+        assertEquals(-4.1422946304E7f, Math.scalb(-1.2345f, 25));
+        assertEquals(-6.98864459991455E-9f, Math.scalb(-0.2345f, -25));
+        assertEquals(2.0f, Math.scalb(Float.MIN_NORMAL / 2, 128));
+        assertEquals(64.0f, Math.scalb(Float.MIN_VALUE, 155));
+        assertEquals(34, Math.getExponent(Math.scalb(1.0f, 34)));
+        assertEquals(3.9999998f, Math
+                .scalb(Float.MAX_VALUE, Float.MIN_EXPONENT));
+
+        // result is near infinity
+        float halfMax = Math.scalb(1.0f, Float.MAX_EXPONENT);
+        assertEquals(1.7014118E38f, halfMax);
+        assertEquals(Float.MAX_VALUE, halfMax - Math.ulp(halfMax) + halfMax);
+        assertEquals(Float.POSITIVE_INFINITY, halfMax + halfMax);
+        assertEquals(3.4028233E38f, Math.scalb(1.0f - Math.ulp(1.0f),
+                Float.MAX_EXPONENT + 1));
+        assertEquals(Float.POSITIVE_INFINITY, Math.scalb(1.0f - Math.ulp(1.0f),
+                Float.MAX_EXPONENT + 2));
+
+        halfMax = Math.scalb(-1.0f, Float.MAX_EXPONENT);
+        assertEquals(-1.7014118E38f, halfMax);
+        assertEquals(-Float.MAX_VALUE, halfMax + Math.ulp(halfMax) + halfMax);
+        assertEquals(Float.NEGATIVE_INFINITY, halfMax + halfMax);
+
+        assertEquals(Float.POSITIVE_INFINITY, Math.scalb(0.345f, 1234));
+        assertEquals(Float.POSITIVE_INFINITY, Math.scalb(44.345E10f, 934));
+        assertEquals(Float.NEGATIVE_INFINITY, Math.scalb(-44.345E10f, 934));
+
+        assertEquals(Float.POSITIVE_INFINITY, Math.scalb(Float.MIN_NORMAL / 2,
+                400));
+        assertEquals(Float.POSITIVE_INFINITY, Math.scalb(Float.MIN_VALUE, 800));
+        assertEquals(Float.POSITIVE_INFINITY, Math.scalb(Float.MAX_VALUE, 1));
+        assertEquals(Float.POSITIVE_INFINITY, Math.scalb(
+                Float.POSITIVE_INFINITY, 0));
+        assertEquals(Float.POSITIVE_INFINITY, Math.scalb(
+                Float.POSITIVE_INFINITY, -1));
+        assertEquals(Float.NEGATIVE_INFINITY, Math.scalb(
+                Float.NEGATIVE_INFINITY, -1));
+        assertEquals(Float.NEGATIVE_INFINITY, Math.scalb(
+                Float.NEGATIVE_INFINITY, Float.MIN_EXPONENT));
+
+        // result is subnormal/zero
+        int posZeroBits = Float.floatToIntBits(+0.0f);
+        int negZeroBits = Float.floatToIntBits(-0.0f);
+        assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(+0.0f,
+                Integer.MAX_VALUE)));
+        assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(+0.0f, -123)));
+        assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(+0.0f, 0)));
+        assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(-0.0f, 123)));
+        assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(-0.0f,
+                Integer.MIN_VALUE)));
+
+        assertEquals(Float.MIN_VALUE, Math.scalb(1.0f, -149));
+        assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(1.0f, -150)));
+        assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(-1.0f, -150)));
+
+        // precision lost
+        assertEquals(Math.scalb(21.405f, -154), Math.scalb(21.405f, -153));
+        assertEquals(Float.MIN_VALUE, Math.scalb(21.405f, -154));
+        assertEquals(-Float.MIN_VALUE, Math.scalb(-21.405f, -154));
+        assertEquals(posZeroBits, Float.floatToIntBits(Math
+                .scalb(21.405f, -155)));
+        assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(-21.405f,
+                -155)));
+        assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(
+                Float.MIN_VALUE, -1)));
+        assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(
+                -Float.MIN_VALUE, -1)));
+        assertEquals(Float.MIN_VALUE, Math.scalb(Float.MIN_NORMAL, -23));
+        assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(
+                Float.MIN_NORMAL, -24)));
+        assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(
+                -Float.MIN_NORMAL, -24)));
+        assertEquals(Float.MIN_VALUE, Math.scalb(Float.MAX_VALUE, -277));
+        assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(
+                Float.MAX_VALUE, -278)));
+        assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(
+                -Float.MAX_VALUE, -278)));
+        assertEquals(Float.MIN_VALUE, Math.scalb(Float.MIN_NORMAL / 3, -22));
+        assertEquals(posZeroBits, Float.floatToIntBits(Math.scalb(
+                Float.MIN_NORMAL / 3, -23)));
+        assertEquals(negZeroBits, Float.floatToIntBits(Math.scalb(
+                -Float.MIN_NORMAL / 3, -23)));
+        float subnormal = Math.scalb(Float.MIN_NORMAL / 3, -11);
+        assertEquals(1.913E-42f, subnormal);
+        // precision lost
+        assertFalse(Float.MIN_NORMAL / 3 == Math.scalb(subnormal, 11));
+
+        assertEquals(68747264, Float.floatToIntBits(Math.scalb(
+                Float.MIN_VALUE * 153, 23)));
+        assertEquals(-2078736384, Float.floatToIntBits(Math.scalb(
+                -Float.MIN_VALUE * 153, 23)));
+
+        assertEquals(4896, Float.floatToIntBits(Math.scalb(
+                Float.MIN_VALUE * 153, 5)));
+        assertEquals(-2147478752, Float.floatToIntBits(Math.scalb(
+                -Float.MIN_VALUE * 153, 5)));
+
+        // NaN
+        assertTrue(Float.isNaN(Math.scalb(Float.NaN, 1)));
+        assertTrue(Float.isNaN(Math.scalb(Float.NaN, 0)));
+        assertTrue(Float.isNaN(Math.scalb(Float.NaN, -120)));
+
+        // test for exception
+        try {
+            Math.scalb((Float) null, (Integer) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            Math.scalb(1.0f, (Integer) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            Math.scalb((Float) null, 1);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        
+        int b1em126 = 0x00800000; // bit representation of Float.MIN_NORMAL
+        int b1em127 = 0x00400000; // bit representation of half
+                                    // Float.MIN_NORMAL
+        // assert exact identity
+        assertEquals(b1em127, Float.floatToIntBits(Math.scalb(Float
+                .intBitsToFloat(b1em126), -1)));
     }
     
     /**
      * @tests java.lang.Math#signum(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "signum",
-        args = {double.class}
-    )
     public void test_signum_D() {
         assertTrue(Double.isNaN(Math.signum(Double.NaN)));
         assertTrue(Double.isNaN(Math.signum(Double.NaN)));
@@ -955,12 +1668,6 @@
     /**
      * @tests java.lang.Math#signum(float)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "signum",
-        args = {float.class}
-    )
     public void test_signum_F() {
         assertTrue(Float.isNaN(Math.signum(Float.NaN)));
         assertEquals(Float.floatToIntBits(0.0f), Float
@@ -983,40 +1690,18 @@
         assertEquals(-1.0f, Math.signum(Float.NEGATIVE_INFINITY), 0f);
     }
 
-    /**
+	/**
      * @tests java.lang.Math#sin(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "sin",
-        args = {double.class}
-    )
-    public void test_sinD() {
-        // Test for method double java.lang.Math.sin(double)
-        assertEquals("Incorrect answer", 0.0, Math.sin(0), 0D);
-        assertEquals("Incorrect answer", 0.8414709848078965, Math.sin(1), 0D);
-        
-        double [] args = {Double.NaN, Double.POSITIVE_INFINITY, 
-                          Double.NEGATIVE_INFINITY};
-        for(int i = 0; i < args.length; i++) {
-            assertEquals("Incorrest returned value.", Double.NaN, 
-                                                             Math.sin(args[i]));
-        }
-        
-        assertEquals("Incorrest returned value.", 0.0, Math.sin(0.0));
-        assertEquals("Incorrest returned value.", -0.0, Math.sin(-0.0));        
-    }
+	public void test_sinD() {
+		// Test for method double java.lang.Math.sin(double)
+		assertEquals("Incorrect answer", 0.0, Math.sin(0), 0D);
+		assertEquals("Incorrect answer", 0.8414709848078965, Math.sin(1), 0D);
+	}
     
     /**
      * @tests java.lang.Math#sinh(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "sinh",
-        args = {double.class}
-    )
     public void test_sinh_D() {
         // Test for special situations
         assertTrue("Should return NaN", Double.isNaN(Math.sinh(Double.NaN)));
@@ -1025,11 +1710,11 @@
         assertEquals("Should return NEGATIVE_INFINITY",
                 Double.NEGATIVE_INFINITY, Math.sinh(Double.NEGATIVE_INFINITY), 0D);
         assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
-                .sinh(0.0)));
-        assertEquals(Double.doubleToLongBits(+0.0), Double
-                .doubleToLongBits(Math.sinh(+0.0)));
-        assertEquals(Double.doubleToLongBits(-0.0), Double
-                .doubleToLongBits(Math.sinh(-0.0)));
+				.sinh(0.0)));
+		assertEquals(Double.doubleToLongBits(+0.0), Double
+				.doubleToLongBits(Math.sinh(+0.0)));
+		assertEquals(Double.doubleToLongBits(-0.0), Double
+				.doubleToLongBits(Math.sinh(-0.0)));
 
         assertEquals("Should return POSITIVE_INFINITY",
                 Double.POSITIVE_INFINITY, Math.sinh(1234.56), 0D);
@@ -1047,62 +1732,27 @@
                 .sinh(Double.MIN_VALUE), 0D);
     }
     
-    /**
-     * @tests java.lang.Math#sqrt(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "sqrt",
-        args = {double.class}
-    )
-    public void test_sqrtD() {
-        // Test for method double java.lang.Math.sqrt(double)
-        assertEquals("Incorrect root returned2", 7, Math.sqrt(49), 0);
-        assertEquals("Incorrect value is returned", Double.NaN, 
-                                                         Math.sqrt(Double.NaN));
-        assertEquals("Incorrect value is returned", Double.NaN, 
-                                                                 Math.sqrt(-1)); 
-        assertEquals("Incorrect value is returned", Double.POSITIVE_INFINITY, 
-                                           Math.sqrt(Double.POSITIVE_INFINITY));
-        assertEquals("Incorrect value is returned", 0.0, Math.sqrt(0.0));         
-        assertEquals("Incorrect value is returned", -0.0, Math.sqrt(-0.0));        
-    }
+	/**
+	 * @tests java.lang.Math#sqrt(double)
+	 */
+	public void test_sqrtD() {
+		// Test for method double java.lang.Math.sqrt(double)
+                assertEquals("Incorrect root returned2", 7, Math.sqrt(49), 0);
+	}
 
-    /**
-     * @tests java.lang.Math#tan(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "tan",
-        args = {double.class}
-    )
-    public void test_tanD() {
-        // Test for method double java.lang.Math.tan(double)
-        assertEquals("Incorrect answer", 0.0, Math.tan(0), 0D);
-        assertEquals("Incorrect answer", 1.5574077246549023, Math.tan(1), 0D);
+	/**
+	 * @tests java.lang.Math#tan(double)
+	 */
+	public void test_tanD() {
+		// Test for method double java.lang.Math.tan(double)
+		assertEquals("Incorrect answer", 0.0, Math.tan(0), 0D);
+		assertEquals("Incorrect answer", 1.5574077246549023, Math.tan(1), 0D);
 
-        double [] args = {Double.NaN, Double.POSITIVE_INFINITY, 
-                                                      Double.NEGATIVE_INFINITY};
-        for(int i = 0; i < args.length; i++) {
-            assertEquals("Incorrest returned value.", Double.NaN, 
-                                                   Math.tan(args[i]));
-        }
-        
-        assertEquals("Incorrest returned value.", 0.0, Math.tan(0.0));
-        assertEquals("Incorrest returned value.", -0.0, Math.tan(-0.0));        
-    }
+	}
 
     /**
      * @tests java.lang.Math#tanh(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "tanh",
-        args = {double.class}
-    )
     public void test_tanh_D() {
         // Test for special situations
         assertTrue("Should return NaN", Double.isNaN(Math.tanh(Double.NaN)));
@@ -1111,11 +1761,11 @@
         assertEquals("Should return -1.0", -1.0, Math
                 .tanh(Double.NEGATIVE_INFINITY), 0D);
         assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
-                .tanh(0.0)));
-        assertEquals(Double.doubleToLongBits(+0.0), Double
-                .doubleToLongBits(Math.tanh(+0.0)));
-        assertEquals(Double.doubleToLongBits(-0.0), Double
-                .doubleToLongBits(Math.tanh(-0.0)));
+				.tanh(0.0)));
+		assertEquals(Double.doubleToLongBits(+0.0), Double
+				.doubleToLongBits(Math.tanh(+0.0)));
+		assertEquals(Double.doubleToLongBits(-0.0), Double
+				.doubleToLongBits(Math.tanh(-0.0)));
 
         assertEquals("Should return 1.0", 1.0, Math.tanh(1234.56), 0D);
         assertEquals("Should return -1.0", -1.0, Math.tanh(-1234.56), 0D);
@@ -1128,144 +1778,210 @@
                 .tanh(Double.MIN_VALUE), 0D);
     }
     
-    /**
-     * @tests java.lang.Math#random()
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "random",
-        args = {}
-    )
-    public void test_random() {
-        // There isn't a place for these tests so just stick them here
-        assertEquals("Wrong value E",
-                4613303445314885481L, Double.doubleToLongBits(Math.E));
-        assertEquals("Wrong value PI",
-                4614256656552045848L, Double.doubleToLongBits(Math.PI));
+	/**
+	 * @tests java.lang.Math#random()
+	 */
+	public void test_random() {
+		// There isn't a place for these tests so just stick them here
+		assertEquals("Wrong value E",
+				4613303445314885481L, Double.doubleToLongBits(Math.E));
+		assertEquals("Wrong value PI",
+				4614256656552045848L, Double.doubleToLongBits(Math.PI));
 
-        for (int i = 500; i >= 0; i--) {
-            double d = Math.random();
-            assertTrue("Generated number is out of range: " + d, d >= 0.0
-                    && d < 1.0);
-        }
-    }
+		for (int i = 500; i >= 0; i--) {
+			double d = Math.random();
+			assertTrue("Generated number is out of range: " + d, d >= 0.0
+					&& d < 1.0);
+		}
+	}
 
-    /**
-     * @tests java.lang.Math#toRadians(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "toRadians",
-        args = {double.class}
-    )
-    public void test_toRadiansD() {
-        for (double d = 500; d >= 0; d -= 1.0) {
-            double converted = Math.toDegrees(Math.toRadians(d));
-            assertTrue("Converted number not equal to original. d = " + d,
-                    converted >= d * 0.99999999 && converted <= d * 1.00000001);
-        }
-    }
+	/**
+	 * @tests java.lang.Math#toRadians(double)
+	 */
+	public void test_toRadiansD() {
+		for (double d = 500; d >= 0; d -= 1.0) {
+			double converted = Math.toDegrees(Math.toRadians(d));
+			assertTrue("Converted number not equal to original. d = " + d,
+					converted >= d * 0.99999999 && converted <= d * 1.00000001);
+		}
+	}
 
-    /**
-     * @tests java.lang.Math#toDegrees(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "toDegrees",
-        args = {double.class}
-    )
-    public void test_toDegreesD() {
-        for (double d = 500; d >= 0; d -= 1.0) {
-            double converted = Math.toRadians(Math.toDegrees(d));
-            assertTrue("Converted number not equal to original. d = " + d,
-                    converted >= d * 0.99999999 && converted <= d * 1.00000001);
-        }
-    }
-    
-    /**
+	/**
+	 * @tests java.lang.Math#toDegrees(double)
+	 */
+	public void test_toDegreesD() {
+		for (double d = 500; d >= 0; d -= 1.0) {
+			double converted = Math.toRadians(Math.toDegrees(d));
+			assertTrue("Converted number not equal to original. d = " + d,
+					converted >= d * 0.99999999 && converted <= d * 1.00000001);
+		}
+	}
+	
+	/**
      * @tests java.lang.Math#ulp(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "ulp",
-        args = {double.class}
-    )
     @SuppressWarnings("boxing")
     public void test_ulp_D() {
-        // Test for special cases
-        assertTrue("Should return NaN", Double.isNaN(Math.ulp(Double.NaN)));
-        assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY, Math
-                .ulp(Double.POSITIVE_INFINITY), 0D);
-        assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY, Math
-                .ulp(Double.NEGATIVE_INFINITY), 0D);
-        assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
-                .ulp(0.0), 0D);
-        assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
-                .ulp(+0.0), 0D);
-        assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
-                .ulp(-0.0), 0D);
-        assertEquals("Returned incorrect value", Math.pow(2, 971), Math
-                .ulp(Double.MAX_VALUE), 0D);
-        assertEquals("Returned incorrect value", Math.pow(2, 971), Math
-                .ulp(-Double.MAX_VALUE), 0D);
+		// Test for special cases
+		assertTrue("Should return NaN", Double.isNaN(Math.ulp(Double.NaN)));
+		assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY, Math
+				.ulp(Double.POSITIVE_INFINITY), 0D);
+		assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY, Math
+				.ulp(Double.NEGATIVE_INFINITY), 0D);
+		assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+				.ulp(0.0), 0D);
+		assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+				.ulp(+0.0), 0D);
+		assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+				.ulp(-0.0), 0D);
+		assertEquals("Returned incorrect value", Math.pow(2, 971), Math
+				.ulp(Double.MAX_VALUE), 0D);
+		assertEquals("Returned incorrect value", Math.pow(2, 971), Math
+				.ulp(-Double.MAX_VALUE), 0D);
 
-        assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
-                .ulp(Double.MIN_VALUE), 0D);
-        assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
-                .ulp(-Double.MIN_VALUE), 0D);
+		assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+				.ulp(Double.MIN_VALUE), 0D);
+		assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+				.ulp(-Double.MIN_VALUE), 0D);
 
-        assertEquals("Returned incorrect value", 2.220446049250313E-16, Math
-                .ulp(1.0), 0D);
-        assertEquals("Returned incorrect value", 2.220446049250313E-16, Math
-                .ulp(-1.0), 0D);
-        assertEquals("Returned incorrect value", 2.2737367544323206E-13, Math
-                .ulp(1153.0), 0D);
+		assertEquals("Returned incorrect value", 2.220446049250313E-16, Math
+				.ulp(1.0), 0D);
+		assertEquals("Returned incorrect value", 2.220446049250313E-16, Math
+				.ulp(-1.0), 0D);
+		assertEquals("Returned incorrect value", 2.2737367544323206E-13, Math
+				.ulp(1153.0), 0D);
+	}
+
+	/**
+	 * @tests java.lang.Math#ulp(float)
+	 */
+	@SuppressWarnings("boxing")
+	public void test_ulp_f() {
+		// Test for special cases
+		assertTrue("Should return NaN", Float.isNaN(Math.ulp(Float.NaN)));
+		assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY, Math
+				.ulp(Float.POSITIVE_INFINITY), 0f);
+		assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY, Math
+				.ulp(Float.NEGATIVE_INFINITY), 0f);
+		assertEquals("Returned incorrect value", Float.MIN_VALUE, Math
+				.ulp(0.0f), 0f);
+		assertEquals("Returned incorrect value", Float.MIN_VALUE, Math
+				.ulp(+0.0f), 0f);
+		assertEquals("Returned incorrect value", Float.MIN_VALUE, Math
+				.ulp(-0.0f), 0f);
+		assertEquals("Returned incorrect value", 2.028241E31f, Math
+				.ulp(Float.MAX_VALUE), 0f);
+		assertEquals("Returned incorrect value", 2.028241E31f, Math
+				.ulp(-Float.MAX_VALUE), 0f);
+
+		assertEquals("Returned incorrect value", 1.4E-45f, Math
+				.ulp(Float.MIN_VALUE), 0f);
+		assertEquals("Returned incorrect value", 1.4E-45f, Math
+				.ulp(-Float.MIN_VALUE), 0f);
+
+		assertEquals("Returned incorrect value", 1.1920929E-7f, Math.ulp(1.0f),
+				0f);
+		assertEquals("Returned incorrect value", 1.1920929E-7f,
+				Math.ulp(-1.0f), 0f);
+		assertEquals("Returned incorrect value", 1.2207031E-4f, Math
+				.ulp(1153.0f), 0f);
+		assertEquals("Returned incorrect value", 5.6E-45f, Math
+				.ulp(9.403954E-38f), 0f);
+    }
+	
+	/**
+     * @tests {@link java.lang.Math#shiftIntBits(int, int)}
+     * 
+     * @since 1.6 
+     */
+    public void test_shiftIntBits_II() {
+        class Tuple {
+            public int result;
+
+            public int value;
+
+            public int factor;
+
+            public Tuple(int result, int value, int factor) {
+                this.result = result;
+                this.value = value;
+                this.factor = factor;
+            }
+        }
+        final Tuple[] TUPLES = new Tuple[] {
+        // sub-normal to sub-normal
+                new Tuple(0x00000000, 0x00000001, -1),
+                // round to even
+                new Tuple(0x00000002, 0x00000003, -1),
+                // round to even
+                new Tuple(0x00000001, 0x00000005, -3),
+                // round to infinity
+                new Tuple(0x00000002, 0x0000000d, -3),
+                // round to infinity
+
+                // normal to sub-normal
+                new Tuple(0x00000002, 0x01a00000, -24),
+                // round to even 
+                new Tuple(0x00000004, 0x01e00000, -24),
+                // round to even
+                new Tuple(0x00000003, 0x01c80000, -24),
+                // round to infinity
+                new Tuple(0x00000004, 0x01e80000, -24),
+        // round to infinity
+        };
+        for (int i = 0; i < TUPLES.length; ++i) {
+            Tuple tuple = TUPLES[i];
+            assertEquals(tuple.result, Float.floatToIntBits(Math.scalb(Float
+                    .intBitsToFloat(tuple.value), tuple.factor)));
+            assertEquals(tuple.result, Float.floatToIntBits(-Math.scalb(-Float
+                    .intBitsToFloat(tuple.value), tuple.factor)));
+        }
     }
 
     /**
-     * @tests java.lang.Math#ulp(float)
+     * @tests {@link java.lang.Math#shiftLongBits(long, long)}
+     * 
+     * Round result to nearest value on precision lost.
+     * 
+     * @since 1.6 
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "ulp",
-        args = {float.class}
-    )
-    @SuppressWarnings("boxing")
-    public void test_ulp_f() {
-        // Test for special cases
-        assertTrue("Should return NaN", Float.isNaN(Math.ulp(Float.NaN)));
-        assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY, Math
-                .ulp(Float.POSITIVE_INFINITY), 0f);
-        assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY, Math
-                .ulp(Float.NEGATIVE_INFINITY), 0f);
-        assertEquals("Returned incorrect value", Float.MIN_VALUE, Math
-                .ulp(0.0f), 0f);
-        assertEquals("Returned incorrect value", Float.MIN_VALUE, Math
-                .ulp(+0.0f), 0f);
-        assertEquals("Returned incorrect value", Float.MIN_VALUE, Math
-                .ulp(-0.0f), 0f);
-        assertEquals("Returned incorrect value", 2.028241E31f, Math
-                .ulp(Float.MAX_VALUE), 0f);
-        assertEquals("Returned incorrect value", 2.028241E31f, Math
-                .ulp(-Float.MAX_VALUE), 0f);
+    public void test_shiftLongBits_LL() {
+        class Tuple {
+            public long result;
 
-        assertEquals("Returned incorrect value", 1.4E-45f, Math
-                .ulp(Float.MIN_VALUE), 0f);
-        assertEquals("Returned incorrect value", 1.4E-45f, Math
-                .ulp(-Float.MIN_VALUE), 0f);
+            public long value;
 
-        assertEquals("Returned incorrect value", 1.1920929E-7f, Math.ulp(1.0f),
-                0f);
-        assertEquals("Returned incorrect value", 1.1920929E-7f,
-                Math.ulp(-1.0f), 0f);
-        assertEquals("Returned incorrect value", 1.2207031E-4f, Math
-                .ulp(1153.0f), 0f);
-        assertEquals("Returned incorrect value", 5.6E-45f, Math
-                .ulp(9.403954E-38f), 0f);
+            public int factor;
+
+            public Tuple(long result, long value, int factor) {
+                this.result = result;
+                this.value = value;
+                this.factor = factor;
+            }
+        }
+        final Tuple[] TUPLES = new Tuple[] {
+        // sub-normal to sub-normal
+                new Tuple(0x00000000L, 0x00000001L, -1),
+                //round to even
+                new Tuple(0x00000002L, 0x00000003L, -1),
+                //round to even
+                new Tuple(0x00000001L, 0x00000005L, -3),
+                //round to infinity
+                new Tuple(0x00000002L, 0x0000000dL, -3),
+                //round to infinity
+
+                // normal to sub-normal
+                new Tuple(0x0000000000000002L, 0x0034000000000000L, -53), // round to even
+                new Tuple(0x0000000000000004L, 0x003c000000000000L, -53), // round to even
+                new Tuple(0x0000000000000003L, 0x0035000000000000L, -53), // round to infinity
+                new Tuple(0x0000000000000004L, 0x003d000000000000L, -53), // round to infinity
+        };
+        for (int i = 0; i < TUPLES.length; ++i) {
+            Tuple tuple = TUPLES[i];
+            assertEquals(tuple.result, Double.doubleToLongBits(Math.scalb(
+                    Double.longBitsToDouble(tuple.value), tuple.factor)));
+            assertEquals(tuple.result, Double.doubleToLongBits(-Math.scalb(
+                    -Double.longBitsToDouble(tuple.value), tuple.factor)));
+        }
     }
 }
diff --git a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/StrictMathTest.java b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/StrictMathTest.java
index 137676c..831dbf8 100644
--- a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/StrictMathTest.java
+++ b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/StrictMathTest.java
@@ -17,369 +17,113 @@
 
 package org.apache.harmony.luni.tests.java.lang;
 
-import dalvik.annotation.TestTargets;
-import dalvik.annotation.TestLevel;
-import dalvik.annotation.TestTargetNew;
-import dalvik.annotation.TestTargetClass;
+import static org.apache.harmony.luni.tests.java.lang.MathTest.COPYSIGN_DD_CASES;
+import static org.apache.harmony.luni.tests.java.lang.MathTest.COPYSIGN_FF_CASES;
+import static org.apache.harmony.luni.tests.java.lang.MathTest.GETEXPONENT_D_CASES;
+import static org.apache.harmony.luni.tests.java.lang.MathTest.GETEXPONENT_D_RESULTS;
+import static org.apache.harmony.luni.tests.java.lang.MathTest.GETEXPONENT_F_CASES;
+import static org.apache.harmony.luni.tests.java.lang.MathTest.GETEXPONENT_F_RESULTS;
+import static org.apache.harmony.luni.tests.java.lang.MathTest.NEXTAFTER_DD_START_CASES;
+import static org.apache.harmony.luni.tests.java.lang.MathTest.NEXTAFTER_DD_FD_DIRECTION_CASES;
+import static org.apache.harmony.luni.tests.java.lang.MathTest.NEXTAFTER_FD_START_CASES;
 
-@TestTargetClass(StrictMath.class) 
 public class StrictMathTest extends junit.framework.TestCase {
 
-    double HYP = StrictMath.sqrt(2.0);
+	double HYP = StrictMath.sqrt(2.0);
 
-    double OPP = 1.0;
+	double OPP = 1.0;
 
-    double ADJ = 1.0;
+	double ADJ = 1.0;
 
-    /* Required to make previous preprocessor flags work - do not remove */
-    int unused = 0;
+	/* Required to make previous preprocessor flags work - do not remove */
+	int unused = 0;
 
-    /**
-     * @tests java.lang.StrictMath#pow(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "pow",
-        args = {double.class, double.class}
-    )
-    public void test_pow() {
-        // tests changes in fdlibm5.3
-        assertTrue(Double.longBitsToDouble(-4610068591539890326L) == 
-            StrictMath.pow(-1.0000000000000002e+00,4.5035996273704970e+15));
-        assertTrue(Double.longBitsToDouble( 4601023824101950163L) == 
-            StrictMath.pow(-9.9999999999999978e-01,4.035996273704970e+15));
-        
-        assertEquals("Incorrect value was returned.", 1.0, 
-                StrictMath.pow(Double.MAX_VALUE, 0.0));
-        assertEquals("Incorrect value was returned.", 1.0, 
-                StrictMath.pow(Double.MAX_VALUE, -0.0));
-        assertEquals("Incorrect value was returned.", Double.NaN, 
-                StrictMath.pow(Double.MAX_VALUE, Double.NaN)); 
-        assertEquals("Incorrect value was returned.", Double.NaN, 
-                StrictMath.pow(Double.NaN, 1.0));
-        assertEquals("Incorrect value was returned.", Double.POSITIVE_INFINITY, 
-                StrictMath.pow(1.1, Double.POSITIVE_INFINITY));    
-        assertEquals("Incorrect value was returned.", Double.POSITIVE_INFINITY, 
-                StrictMath.pow(0.9, Double.NEGATIVE_INFINITY));   
-        
-        assertEquals("Incorrect value was returned.", 0.0, 
-                StrictMath.pow(1.1, Double.NEGATIVE_INFINITY));   
-        assertEquals("Incorrect value was returned.", 0.0, 
-                StrictMath.pow(0.9, Double.POSITIVE_INFINITY));    
-        
-        assertEquals("Incorrect value was returned.", Double.NaN, 
-                StrictMath.pow(-1.0, Double.POSITIVE_INFINITY));   
-        assertEquals("Incorrect value was returned.", Double.NaN, 
-                StrictMath.pow(1.0, Double.NEGATIVE_INFINITY));
-        
-        assertEquals("Incorrect value was returned.", 0.0, 
-                StrictMath.pow(0.0, 1.1));   
-        assertEquals("Incorrect value was returned.", 0.0, 
-                StrictMath.pow(Double.POSITIVE_INFINITY, -1.0));   
-        
-        assertEquals("Incorrect value was returned.", 0.0, 
-                StrictMath.pow(-0.0, 1.1));   
-        assertEquals("Incorrect value was returned.", 0.0, 
-                StrictMath.pow(Double.POSITIVE_INFINITY, -1.0)); 
-        
-        assertEquals("Incorrect value was returned.", Double.POSITIVE_INFINITY,
-                StrictMath.pow(0.0, -1.0));
-        assertEquals("Incorrect value was returned.", Double.POSITIVE_INFINITY,
-                StrictMath.pow(Double.POSITIVE_INFINITY, 1.0));        
-        
-        assertEquals("Incorrect value was returned.", 0.0,
-                StrictMath.pow(-0.0, 2.0));
-        assertEquals("Incorrect value was returned.", 0.0,
-                StrictMath.pow(Double.NEGATIVE_INFINITY, -2.0));  
-        
-        assertEquals("Incorrect value was returned.", -0.0,
-                StrictMath.pow(-0.0, 1.0));
-        assertEquals("Incorrect value was returned.", -0.0,
-                StrictMath.pow(Double.NEGATIVE_INFINITY, -1.0));  
-        
-        assertEquals("Incorrect value was returned.", Double.POSITIVE_INFINITY,
-                StrictMath.pow(-0.0, -2.0));
-        assertEquals("Incorrect value was returned.", Double.POSITIVE_INFINITY,
-                StrictMath.pow(Double.NEGATIVE_INFINITY, 2.0)); 
-        
-        assertEquals("Incorrect value was returned.", Double.NEGATIVE_INFINITY,
-                StrictMath.pow(-0.0, -1.0));
-        assertEquals("Incorrect value was returned.", Double.NEGATIVE_INFINITY,
-                StrictMath.pow(Double.NEGATIVE_INFINITY, 1.0));   
-        
-        assertEquals("Incorrect value was returned.", -0.999,
-                StrictMath.pow(-0.999, 1.0));   
-        
-        assertEquals("Incorrect value was returned.", Double.NaN,
-                StrictMath.pow(-0.999, 1.1));
-    }
+	/**
+	 * @tests java.lang.StrictMath#abs(double)
+	 */
+	public void test_absD() {
+		// Test for method double java.lang.StrictMath.abs(double)
 
-    /**
-     * @tests java.lang.StrictMath#tan(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "tan",
-        args = {double.class}
-    )
-    public void test_tan(){
-        // tests changes in fdlibm5.3
-        assertTrue(Double.longBitsToDouble( 4850236541654588678L) == StrictMath.tan( 1.7765241907548024E+269));
-        assertEquals("Incorrect value of tan was returned.",
-                Double.NaN, StrictMath.tan(Double.NaN));
-        assertEquals("Incorrect value of tan was returned.",
-                Double.NaN, StrictMath.tan(Double.POSITIVE_INFINITY));     
-        assertEquals("Incorrect value of tan was returned.",
-                Double.NaN, StrictMath.tan(Double.NEGATIVE_INFINITY));
-        assertEquals("Incorrect value of tan was returned.",
-                0.0, StrictMath.tan(0.0));    
-        assertEquals("Incorrect value of tan was returned.",
-                -0.0, StrictMath.tan(-0.0));            
-    }
+		assertTrue("Incorrect double abs value",
+				(StrictMath.abs(-1908.8976) == 1908.8976));
+		assertTrue("Incorrect double abs value",
+				(StrictMath.abs(1908.8976) == 1908.8976));
+	}
 
-    /**
-     * @tests java.lang.StrictMath#asin(double)
-     * @tests java.lang.StrictMath#exp(double)
-     * @tests java.lang.StrictMath#sinh(double)
-     * @tests java.lang.StrictMath#expm1(double)
-     */
-    @TestTargets({
-        @TestTargetNew(
-            level = TestLevel.PARTIAL,
-            notes = "Checks one value.",
-            method = "asin",
-            args = {double.class}
-        ),
-        @TestTargetNew(
-            level = TestLevel.PARTIAL,
-            notes = "Checks one value.",
-            method = "exp",
-            args = {double.class}
-        ),
-        @TestTargetNew(
-            level = TestLevel.PARTIAL,
-            notes = "Checks one value.",
-            method = "sinh",
-            args = {double.class}
-        ),
-        @TestTargetNew(
-            level = TestLevel.PARTIAL,
-            notes = "Checks one value.",
-            method = "expm1",
-            args = {double.class}
-        )
-    })
-    public void test_inexact(){
-        assertTrue( 4485585228743840298L == Double.doubleToRawLongBits(StrictMath.asin(7.4505805E-9)));
-        assertTrue( 4607182418816794624L == Double.doubleToRawLongBits(StrictMath.exp(3.7252902E-9)));
-        assertTrue( 4481081628995577220L == Double.doubleToRawLongBits(StrictMath.sinh(3.7252902E-9)));
-        assertTrue(-4616189618054758400L == Double.doubleToRawLongBits(StrictMath.expm1(-40)));
-    }
-    
-    /**
-     * @tests java.lang.StrictMath#abs(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "abs",
-        args = {double.class}
-    )
-    public void test_absD() {
-        // Test for method double java.lang.StrictMath.abs(double)
+	/**
+	 * @tests java.lang.StrictMath#abs(float)
+	 */
+	public void test_absF() {
+		// Test for method float java.lang.StrictMath.abs(float)
+		assertTrue("Incorrect float abs value",
+				(StrictMath.abs(-1908.8976f) == 1908.8976f));
+		assertTrue("Incorrect float abs value",
+				(StrictMath.abs(1908.8976f) == 1908.8976f));
+	}
 
-        assertTrue("Incorrect double abs value",
-                (StrictMath.abs(-1908.8976) == 1908.8976));
-        assertTrue("Incorrect double abs value",
-                (StrictMath.abs(1908.8976) == 1908.8976));
-        
-        assertEquals(0.0, StrictMath.abs(0.0));
-        assertEquals(0.0, StrictMath.abs(-0.0));
-        assertEquals(Double.POSITIVE_INFINITY, StrictMath.abs(Double.POSITIVE_INFINITY));    
-        assertEquals(Double.POSITIVE_INFINITY, StrictMath.abs(Double.NEGATIVE_INFINITY));      
-        assertEquals(Double.NaN, StrictMath.abs(Double.NaN));      
-    }
+	/**
+	 * @tests java.lang.StrictMath#abs(int)
+	 */
+	public void test_absI() {
+		// Test for method int java.lang.StrictMath.abs(int)
+		assertTrue("Incorrect int abs value",
+				(StrictMath.abs(-1908897) == 1908897));
+		assertTrue("Incorrect int abs value",
+				(StrictMath.abs(1908897) == 1908897));
+	}
 
-    /**
-     * @tests java.lang.StrictMath#abs(float)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "abs",
-        args = {float.class}
-    )
-    public void test_absF() {
-        // Test for method float java.lang.StrictMath.abs(float)
-        assertTrue("Incorrect float abs value",
-                (StrictMath.abs(-1908.8976f) == 1908.8976f));
-        assertTrue("Incorrect float abs value",
-                (StrictMath.abs(1908.8976f) == 1908.8976f));
-        
-        assertEquals(0f, StrictMath.abs(0f));
-        assertEquals(0f, StrictMath.abs(-0f));
-        assertEquals(Float.POSITIVE_INFINITY, StrictMath.abs(Float.POSITIVE_INFINITY));    
-        assertEquals(Float.POSITIVE_INFINITY, StrictMath.abs(Float.NEGATIVE_INFINITY));      
-        assertEquals(Float.NaN, StrictMath.abs(Float.NaN));        
-    }
+	/**
+	 * @tests java.lang.StrictMath#abs(long)
+	 */
+	public void test_absJ() {
+		// Test for method long java.lang.StrictMath.abs(long)
+		assertTrue("Incorrect long abs value", (StrictMath
+				.abs(-19088976000089L) == 19088976000089L));
+		assertTrue("Incorrect long abs value",
+				(StrictMath.abs(19088976000089L) == 19088976000089L));
+	}
 
-    /**
-     * @tests java.lang.StrictMath#abs(int)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "abs",
-        args = {int.class}
-    )
-    public void test_absI() {
-        // Test for method int java.lang.StrictMath.abs(int)
-        assertTrue("Incorrect int abs value",
-                (StrictMath.abs(-1908897) == 1908897));
-        assertTrue("Incorrect int abs value",
-                (StrictMath.abs(1908897) == 1908897));
-        
-        assertEquals(Integer.MIN_VALUE, StrictMath.abs(Integer.MIN_VALUE));
-    }
+	/**
+	 * @tests java.lang.StrictMath#acos(double)
+	 */
+	public void test_acosD() {
+		// Test for method double java.lang.StrictMath.acos(double)
+		assertTrue("Returned incorrect arc cosine", StrictMath.cos(StrictMath
+				.acos(ADJ / HYP)) == ADJ / HYP);
+	}
 
-    /**
-     * @tests java.lang.StrictMath#abs(long)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "abs",
-        args = {long.class}
-    )
-    public void test_absJ() {
-        // Test for method long java.lang.StrictMath.abs(long)
-        assertTrue("Incorrect long abs value", (StrictMath
-                .abs(-19088976000089L) == 19088976000089L));
-        assertTrue("Incorrect long abs value",
-                (StrictMath.abs(19088976000089L) == 19088976000089L));
-        
-        assertEquals(Long.MIN_VALUE, StrictMath.abs(Long.MIN_VALUE));        
-    }
+	/**
+	 * @tests java.lang.StrictMath#asin(double)
+	 */
+	public void test_asinD() {
+		// Test for method double java.lang.StrictMath.asin(double)
+		assertTrue("Returned incorrect arc sine", StrictMath.sin(StrictMath
+				.asin(OPP / HYP)) == OPP / HYP);
+	}
 
-    /**
-     * @tests java.lang.StrictMath#acos(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "acos",
-        args = {double.class}
-    )
-    public void test_acosD() {
-        // Test for method double java.lang.StrictMath.acos(double)
-        assertTrue("Returned incorrect arc cosine", StrictMath.cos(StrictMath
-                .acos(ADJ / HYP)) == ADJ / HYP);
-        
-        assertEquals(Double.NaN, StrictMath.acos(Double.NaN));
-        assertEquals(Double.NaN, StrictMath.acos(1.1));        
-    }
+	/**
+	 * @tests java.lang.StrictMath#atan(double)
+	 */
+	public void test_atanD() {
+		// Test for method double java.lang.StrictMath.atan(double)
+		double answer = StrictMath.tan(StrictMath.atan(1.0));
+		assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
+				&& answer >= 9.9999999999999983E-1);
+	}
 
-    /**
-     * @tests java.lang.StrictMath#asin(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "asin",
-        args = {double.class}
-    )
-    public void test_asinD() {
-        // Test for method double java.lang.StrictMath.asin(double)
-        assertTrue("Returned incorrect arc sine", StrictMath.sin(StrictMath
-                .asin(OPP / HYP)) == OPP / HYP);
-        
-        assertEquals(Double.NaN, StrictMath.asin(Double.NaN));
-        assertEquals(Double.NaN, StrictMath.asin(1.1));        
-        assertEquals(0.0, StrictMath.asin(0.0));  
-        assertEquals(-0.0, StrictMath.asin(-0.0));          
-    }
-
-    /**
-     * @tests java.lang.StrictMath#atan(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "Doesn't check boundary values.",
-        method = "atan",
-        args = {double.class}
-    )
-    public void test_atanD() {
-        // Test for method double java.lang.StrictMath.atan(double)
-        double answer = StrictMath.tan(StrictMath.atan(1.0));
-        assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
-                && answer >= 9.9999999999999983E-1);
-    }
-
-    /**
-     * @tests java.lang.StrictMath#atan2(double, double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "atan2",
-        args = {double.class, double.class}
-    )
-    public void test_atan2DD() {
-        // Test for method double java.lang.StrictMath.atan2(double, double)
-        double answer = StrictMath.atan(StrictMath.tan(1.0));
-        assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
-                && answer >= 9.9999999999999983E-1);
-        
-        assertEquals(Double.NaN, StrictMath.atan2(Double.NaN, 1.0));
-        assertEquals(Double.NaN, StrictMath.atan2(Double.NaN, 1.0));
-        
-        assertEquals(0.0, StrictMath.atan2(0.0, 1.0));
-        assertEquals(0.0, StrictMath.atan2(1.0, Double.POSITIVE_INFINITY));   
-        
-        assertEquals(-0.0, StrictMath.atan2(-0.0, 1.0));      
-        assertEquals(-0.0, StrictMath.atan2(-1.0, Double.POSITIVE_INFINITY)); 
-        
-        assertEquals(StrictMath.PI, StrictMath.atan2(0.0, -1.0));      
-        assertEquals(StrictMath.PI, StrictMath.atan2(1.0, 
-                                                     Double.NEGATIVE_INFINITY));     
-        
-        assertEquals(-StrictMath.PI, StrictMath.atan2(-0.0, -1.0));   
-        assertEquals(-StrictMath.PI, StrictMath.atan2(-1.0, 
-                                                     Double.NEGATIVE_INFINITY));     
-        
-        assertEquals(StrictMath.PI/2, StrictMath.atan2(1.0, 0.0));   
-        assertEquals(StrictMath.PI/2, StrictMath.atan2(1.0, -0.0));        
-        assertEquals(StrictMath.PI/2, StrictMath.atan2(Double.POSITIVE_INFINITY, 0.0)); 
-        
-        assertEquals(-StrictMath.PI/2, StrictMath.atan2(-1.0, 0.0));   
-        assertEquals(-StrictMath.PI/2, StrictMath.atan2(-1.0, -0.0));        
-        assertEquals(-StrictMath.PI/2, StrictMath.atan2(Double.NEGATIVE_INFINITY, 1.0));  
-        
-        assertEquals(StrictMath.PI/4, StrictMath.atan2(Double.POSITIVE_INFINITY, 
-                                                     Double.POSITIVE_INFINITY)); 
-        assertEquals(3*StrictMath.PI/4, 
-                                      StrictMath.atan2(Double.POSITIVE_INFINITY, 
-                                                     Double.NEGATIVE_INFINITY));     
-        
-        assertEquals(-StrictMath.PI/4, 
-                StrictMath.atan2(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));  
-        
-        assertEquals(-3*StrictMath.PI/4, 
-                                      StrictMath.atan2(Double.NEGATIVE_INFINITY, 
-                                                     Double.NEGATIVE_INFINITY));        
-    }
+	/**
+	 * @tests java.lang.StrictMath#atan2(double, double)
+	 */
+	public void test_atan2DD() {
+		// Test for method double java.lang.StrictMath.atan2(double, double)
+		double answer = StrictMath.atan(StrictMath.tan(1.0));
+		assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
+				&& answer >= 9.9999999999999983E-1);
+	}
     
     /**
      * @tests java.lang.StrictMath#cbrt(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "cbrt",
-        args = {double.class}
-    )
     @SuppressWarnings("boxing")
     public void test_cbrt_D() {
         // Test for special situations
@@ -392,11 +136,11 @@
                 Double.NEGATIVE_INFINITY, StrictMath
                         .cbrt(Double.NEGATIVE_INFINITY));
         assertEquals(Double.doubleToLongBits(0.0), Double
-                .doubleToLongBits(StrictMath.cbrt(0.0)));
-        assertEquals(Double.doubleToLongBits(+0.0), Double
-                .doubleToLongBits(StrictMath.cbrt(+0.0)));
-        assertEquals(Double.doubleToLongBits(-0.0), Double
-                .doubleToLongBits(StrictMath.cbrt(-0.0)));
+				.doubleToLongBits(StrictMath.cbrt(0.0)));
+		assertEquals(Double.doubleToLongBits(+0.0), Double
+				.doubleToLongBits(StrictMath.cbrt(+0.0)));
+		assertEquals(Double.doubleToLongBits(-0.0), Double
+				.doubleToLongBits(StrictMath.cbrt(-0.0)));
 
         assertEquals("Should return 3.0", 3.0, StrictMath.cbrt(27.0));
         assertEquals("Should return 23.111993172558684", 23.111993172558684,
@@ -420,67 +164,159 @@
         }
     }
 
-    /**
-     * @tests java.lang.StrictMath#ceil(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "ceil",
-        args = {double.class}
-    )
-    public void test_ceilD() {
-        // Test for method double java.lang.StrictMath.ceil(double)
+	/**
+	 * @tests java.lang.StrictMath#ceil(double)
+	 */
+	public void test_ceilD() {
+		// Test for method double java.lang.StrictMath.ceil(double)
                 assertEquals("Incorrect ceiling for double",
                              79, StrictMath.ceil(78.89), 0.0);
-        assertEquals("Incorrect ceiling for double",
+		assertEquals("Incorrect ceiling for double",
                              -78, StrictMath.ceil(-78.89), 0.0);
+	}
+	
+	/**
+     * @tests {@link java.lang.StrictMath#copySign(double, double)}
+     * @since 1.6
+     */
+    @SuppressWarnings("boxing")
+    public void test_copySign_DD() {
+        for (int i = 0; i < COPYSIGN_DD_CASES.length; i++) {
+            final double magnitude = COPYSIGN_DD_CASES[i];
+            final long absMagnitudeBits = Double.doubleToLongBits(StrictMath
+                    .abs(magnitude));
+            final long negMagnitudeBits = Double.doubleToLongBits(-StrictMath
+                    .abs(magnitude));
+
+            // cases for NaN
+            assertEquals("If the sign is NaN, the result should be positive.",
+                    absMagnitudeBits, Double.doubleToLongBits(StrictMath
+                            .copySign(magnitude, Double.NaN)));
+            assertTrue("The result should be NaN.", Double.isNaN(StrictMath
+                    .copySign(Double.NaN, magnitude)));
+
+            for (int j = 0; j < COPYSIGN_DD_CASES.length; j++) {
+                final double sign = COPYSIGN_DD_CASES[j];
+                final long resultBits = Double.doubleToLongBits(StrictMath
+                        .copySign(magnitude, sign));
+
+                if (sign > 0 || Double.valueOf(+0.0).equals(sign)
+                        || Double.valueOf(0.0).equals(sign)) {
+                    assertEquals(
+                            "If the sign is positive, the result should be positive.",
+                            absMagnitudeBits, resultBits);
+                }
+                if (sign < 0 || Double.valueOf(-0.0).equals(sign)) {
+                    assertEquals(
+                            "If the sign is negative, the result should be negative.",
+                            negMagnitudeBits, resultBits);
+                }
+            }
+        }
+
+        assertTrue("The result should be NaN.", Double.isNaN(StrictMath
+                .copySign(Double.NaN, Double.NaN)));
+
+        try {
+            StrictMath.copySign((Double) null, 2.3);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            StrictMath.copySign(2.3, (Double) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            StrictMath.copySign((Double) null, (Double) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
         
-        assertEquals("Incorrect ceiling for mathematical integer",
-                             -78, StrictMath.ceil(-78), 0.0);  
-        assertEquals("Incorrect ceiling for NaN",
-                                       Double.NaN, StrictMath.ceil(Double.NaN));
-        assertEquals("Incorrect ceiling for positive infinity", 
-                Double.POSITIVE_INFINITY, 
-                StrictMath.ceil(Double.POSITIVE_INFINITY));        
-        assertEquals("Incorrect ceiling for negative infinity", 
-                Double.NEGATIVE_INFINITY, 
-                StrictMath.ceil(Double.NEGATIVE_INFINITY));  
-        assertEquals("Incorrect ceiling for positive zero.", 
-                0.0, StrictMath.ceil(0.0));
-        assertEquals("Incorrect ceiling for negative zero.", 
-                -0.0, StrictMath.ceil(-0.0)); 
-        assertEquals("Incorrect ceiling for negative zero.", 
-                -0.0, StrictMath.ceil(-0.5));         
+		double d = Double.longBitsToDouble(0xfff8000000000000L);
+		assertEquals(1.0, StrictMath.copySign(1.0, d), 0d);
     }
 
     /**
-     * @tests java.lang.StrictMath#cos(double)
+     * @tests {@link java.lang.StrictMath#copySign(float, float)}
+     * @since 1.6
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "cos",
-        args = {double.class}
-    )
-    public void test_cosD() {
-        // Test for method double java.lang.StrictMath.cos(double)
+    @SuppressWarnings("boxing")
+    public void test_copySign_FF() {
+        for (int i = 0; i < COPYSIGN_FF_CASES.length; i++) {
+            final float magnitude = COPYSIGN_FF_CASES[i];
+            final int absMagnitudeBits = Float.floatToIntBits(StrictMath
+                    .abs(magnitude));
+            final int negMagnitudeBits = Float.floatToIntBits(-StrictMath
+                    .abs(magnitude));
 
-        assertTrue("Returned incorrect cosine", StrictMath.cos(StrictMath
-                .acos(ADJ / HYP)) == ADJ / HYP);
-        assertEquals("Returned incorrect cosine", StrictMath.cos(Double.NaN), 
-                                                                 Double.NaN);        
+            // cases for NaN
+            assertEquals("If the sign is NaN, the result should be positive.",
+                    absMagnitudeBits, Float.floatToIntBits(StrictMath.copySign(
+                            magnitude, Float.NaN)));
+            assertTrue("The result should be NaN.", Float.isNaN(StrictMath
+                    .copySign(Float.NaN, magnitude)));
+
+            for (int j = 0; j < COPYSIGN_FF_CASES.length; j++) {
+                final float sign = COPYSIGN_FF_CASES[j];
+                final int resultBits = Float.floatToIntBits(StrictMath
+                        .copySign(magnitude, sign));
+                if (sign > 0 || Float.valueOf(+0.0f).equals(sign)
+                        || Float.valueOf(0.0f).equals(sign)) {
+                    assertEquals(
+                            "If the sign is positive, the result should be positive.",
+                            absMagnitudeBits, resultBits);
+                }
+                if (sign < 0 || Float.valueOf(-0.0f).equals(sign)) {
+                    assertEquals(
+                            "If the sign is negative, the result should be negative.",
+                            negMagnitudeBits, resultBits);
+                }
+            }
+        }
+
+        assertTrue("The result should be NaN.", Float.isNaN(StrictMath
+                .copySign(Float.NaN, Float.NaN)));
+
+        try {
+            StrictMath.copySign((Float) null, 2.3f);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            StrictMath.copySign(2.3f, (Float) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            StrictMath.copySign((Float) null, (Float) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        
+		float f = Float.intBitsToFloat(0xffc00000);
+		assertEquals(1.0f, StrictMath.copySign(1.0f, f), 0f);
     }
+
+	/**
+	 * @tests java.lang.StrictMath#cos(double)
+	 */
+	public void test_cosD() {
+		// Test for method double java.lang.StrictMath.cos(double)
+
+		assertTrue("Returned incorrect cosine", StrictMath.cos(StrictMath
+				.acos(ADJ / HYP)) == ADJ / HYP);
+	}
     
     /**
      * @tests java.lang.StrictMath#cosh(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "cosh",
-        args = {double.class}
-    )
     @SuppressWarnings("boxing")
     public void test_cosh_D() {
         // Test for special situations        
@@ -512,39 +348,21 @@
                 .cosh(Double.MIN_VALUE));
     }
 
-    /**
-     * @tests java.lang.StrictMath#exp(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "exp",
-        args = {double.class}
-    )
-    public void test_expD() {
-        // Test for method double java.lang.StrictMath.exp(double)
-        assertTrue("Incorrect answer returned for simple power", StrictMath
-                .abs(StrictMath.exp(4D) - StrictMath.E * StrictMath.E
-                        * StrictMath.E * StrictMath.E) < 0.1D);
-        assertTrue("Incorrect answer returned for larger power", StrictMath
-                .log(StrictMath.abs(StrictMath.exp(5.5D)) - 5.5D) < 10.0D);
-        assertEquals("Returned incorrect value for NaN argument", Double.NaN, 
-                                                    StrictMath.exp(Double.NaN));
-        assertEquals("Returned incorrect value for positive infinity.", 
-            Double.POSITIVE_INFINITY, StrictMath.exp(Double.POSITIVE_INFINITY));    
-        assertEquals("Returned incorrect value for negative infinity.", 
-                                 0.0, StrictMath.exp(Double.NEGATIVE_INFINITY));  
-    }
+	/**
+	 * @tests java.lang.StrictMath#exp(double)
+	 */
+	public void test_expD() {
+		// Test for method double java.lang.StrictMath.exp(double)
+		assertTrue("Incorrect answer returned for simple power", StrictMath
+				.abs(StrictMath.exp(4D) - StrictMath.E * StrictMath.E
+						* StrictMath.E * StrictMath.E) < 0.1D);
+		assertTrue("Incorrect answer returned for larger power", StrictMath
+				.log(StrictMath.abs(StrictMath.exp(5.5D)) - 5.5D) < 10.0D);
+	}
     
     /**
      * @tests java.lang.StrictMath#expm1(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "expm1",
-        args = {double.class}
-    )
     @SuppressWarnings("boxing")
     public void test_expm1_D() {
         //Test for special cases        
@@ -554,11 +372,11 @@
         assertEquals("Should return -1.0", -1.0, StrictMath
                 .expm1(Double.NEGATIVE_INFINITY));
         assertEquals(Double.doubleToLongBits(0.0), Double
-                .doubleToLongBits(StrictMath.expm1(0.0)));
-        assertEquals(Double.doubleToLongBits(+0.0), Double
-                .doubleToLongBits(StrictMath.expm1(+0.0)));
-        assertEquals(Double.doubleToLongBits(-0.0), Double
-                .doubleToLongBits(StrictMath.expm1(-0.0)));
+				.doubleToLongBits(StrictMath.expm1(0.0)));
+		assertEquals(Double.doubleToLongBits(+0.0), Double
+				.doubleToLongBits(StrictMath.expm1(+0.0)));
+		assertEquals(Double.doubleToLongBits(-0.0), Double
+				.doubleToLongBits(StrictMath.expm1(-0.0)));
 
         assertEquals("Should return -9.999950000166666E-6",
                 -9.999950000166666E-6, StrictMath.expm1(-0.00001));
@@ -574,44 +392,61 @@
        
     }    
 
-    /**
-     * @tests java.lang.StrictMath#floor(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "floor",
-        args = {double.class}
-    )
-    public void test_floorD() {
-        // Test for method double java.lang.StrictMath.floor(double)
+	/**
+	 * @tests java.lang.StrictMath#floor(double)
+	 */
+	public void test_floorD() {
+		// Test for method double java.lang.StrictMath.floor(double)
                 assertEquals("Incorrect floor for double",
                              78, StrictMath.floor(78.89), 0.0);
-        assertEquals("Incorrect floor for double",
+		assertEquals("Incorrect floor for double",
                              -79, StrictMath.floor(-78.89), 0.0);
-        assertEquals("Incorrect floor for mathematical integer",
-                             -79, StrictMath.floor(-79), 0.0);
-        assertEquals("Incorrect floor for NaN",
-                        Double.NaN, StrictMath.floor(Double.NaN));    
-        assertEquals("Incorrect floor for positive infinity.",
-          Double.POSITIVE_INFINITY, StrictMath.floor(Double.POSITIVE_INFINITY));    
-        assertEquals("Incorrect floor for negative infinity.",
-          Double.NEGATIVE_INFINITY, StrictMath.floor(Double.NEGATIVE_INFINITY));  
-        assertEquals("Incorrect floor for positive zero.",
-                                                    0.0, StrictMath.floor(0.0)); 
-        assertEquals("Incorrect floor for negative zero.",
-                                                  -0.0, StrictMath.floor(-0.0));        
+	}
+	
+	/**
+     * @tests {@link java.lang.StrictMath#getExponent(double)}
+     * @since 1.6
+     */
+    @SuppressWarnings("boxing")
+    public void test_getExponent_D() {
+        for (int i = 0; i < GETEXPONENT_D_CASES.length; i++) {
+            final double number = GETEXPONENT_D_CASES[i];
+            final int result = GETEXPONENT_D_RESULTS[i];
+            assertEquals("Wrong result of getExponent(double).", result,
+                    StrictMath.getExponent(number));
+        }
+
+        try {
+            StrictMath.getExponent((Double) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+    }
+
+    /**
+     * @tests {@link java.lang.StrictMath#getExponent(float)}
+     * @since 1.6
+     */
+    @SuppressWarnings("boxing")
+    public void test_getExponent_F() {
+        for (int i = 0; i < GETEXPONENT_F_CASES.length; i++) {
+            final float number = GETEXPONENT_F_CASES[i];
+            final int result = GETEXPONENT_F_RESULTS[i];
+            assertEquals("Wrong result of getExponent(float).", result,
+                    StrictMath.getExponent(number));
+        }
+        try {
+            StrictMath.getExponent((Float) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
     }
     
     /**
      * @tests java.lang.StrictMath#hypot(double, double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "hypot",
-        args = {double.class, double.class}
-    )
     @SuppressWarnings("boxing")
     public void test_hypot_DD() {
         // Test for special cases
@@ -649,77 +484,37 @@
 
     }
 
-    /**
-     * @tests java.lang.StrictMath#IEEEremainder(double, double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "IEEEremainder",
-        args = {double.class, double.class}
-    )
-    public void test_IEEEremainderDD() {
-        // Test for method double java.lang.StrictMath.IEEEremainder(double,
-        // double)
-        assertEquals("Incorrect remainder returned", 0.0, StrictMath.IEEEremainder(
-                1.0, 1.0), 0.0);
-        assertTrue(
-                "Incorrect remainder returned",
-                StrictMath.IEEEremainder(1.32, 89.765) >= 1.4705063220631647E-2
-                        || StrictMath.IEEEremainder(1.32, 89.765) >= 1.4705063220631649E-2);
-        
-        assertEquals(Double.NaN, StrictMath.IEEEremainder(Double.NaN, 0.0));
-        assertEquals(Double.NaN, StrictMath.IEEEremainder(0.0, Double.NaN));
-        assertEquals(Double.NaN, StrictMath.IEEEremainder(Double.POSITIVE_INFINITY, 0.0));
-        assertEquals(Double.NaN, StrictMath.IEEEremainder(Double.NEGATIVE_INFINITY, 0.0));
-        assertEquals(Double.NaN, StrictMath.IEEEremainder(0.0, 0.0));
-        assertEquals(Double.NaN, StrictMath.IEEEremainder(-0.0, 0.0));
-        
-        assertEquals(1.0, StrictMath.IEEEremainder(1.0, Double.POSITIVE_INFINITY));
-        assertEquals(1.0, StrictMath.IEEEremainder(1.0, Double.NEGATIVE_INFINITY));        
-        
-    }
+	/**
+	 * @tests java.lang.StrictMath#IEEEremainder(double, double)
+	 */
+	public void test_IEEEremainderDD() {
+		// Test for method double java.lang.StrictMath.IEEEremainder(double,
+		// double)
+		assertEquals("Incorrect remainder returned", 0.0, StrictMath.IEEEremainder(
+				1.0, 1.0), 0.0);
+		assertTrue(
+				"Incorrect remainder returned",
+				StrictMath.IEEEremainder(1.32, 89.765) >= 1.4705063220631647E-2
+						|| StrictMath.IEEEremainder(1.32, 89.765) >= 1.4705063220631649E-2);
+	}
 
-    /**
-     * @tests java.lang.StrictMath#log(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "log",
-        args = {double.class}
-    )
-    public void test_logD() {
-        // Test for method double java.lang.StrictMath.log(double)
-        for (double d = 10; d >= -10; d -= 0.5) {
-            double answer = StrictMath.log(StrictMath.exp(d));
-            assertTrue("Answer does not equal expected answer for d = " + d
-                    + " answer = " + answer,
-                    StrictMath.abs(answer - d) <= StrictMath
-                            .abs(d * 0.00000001));
-        }
-        
-        assertEquals("Returned incorrect value for NaN.", 
-                                        Double.NaN, StrictMath.log(Double.NaN));
-        assertEquals("Returned incorrect value for positive infinity.", 
-            Double.POSITIVE_INFINITY, StrictMath.log(Double.POSITIVE_INFINITY));     
-        assertEquals("Returned incorrect value for negative infinity.", 
-                          Double.NaN, StrictMath.log(Double.NEGATIVE_INFINITY));  
-        assertEquals("Returned incorrect value for positive zero.", 
-                                 Double.NEGATIVE_INFINITY, StrictMath.log(0.0));  
-        assertEquals("Returned incorrect value for negative zero.", 
-                                Double.NEGATIVE_INFINITY, StrictMath.log(-0.0));        
-    }
+	/**
+	 * @tests java.lang.StrictMath#log(double)
+	 */
+	public void test_logD() {
+		// Test for method double java.lang.StrictMath.log(double)
+		for (double d = 10; d >= -10; d -= 0.5) {
+			double answer = StrictMath.log(StrictMath.exp(d));
+			assertTrue("Answer does not equal expected answer for d = " + d
+					+ " answer = " + answer,
+					StrictMath.abs(answer - d) <= StrictMath
+							.abs(d * 0.00000001));
+		}
+	}
     
     /**
      * @tests java.lang.StrictMath#log10(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "log10",
-        args = {double.class}
-    )
     @SuppressWarnings("boxing")
     public void test_log10_D() {
         // Test for special cases        
@@ -754,12 +549,6 @@
     /**
      * @tests java.lang.StrictMath#log1p(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "log1p",
-        args = {double.class}
-    )
     @SuppressWarnings("boxing")
     public void test_log1p_D() {
         // Test for special cases
@@ -771,11 +560,11 @@
                 Double.POSITIVE_INFINITY, StrictMath
                         .log1p(Double.POSITIVE_INFINITY));
         assertEquals(Double.doubleToLongBits(0.0), Double
-                .doubleToLongBits(StrictMath.log1p(0.0)));
-        assertEquals(Double.doubleToLongBits(+0.0), Double
-                .doubleToLongBits(StrictMath.log1p(+0.0)));
-        assertEquals(Double.doubleToLongBits(-0.0), Double
-                .doubleToLongBits(StrictMath.log1p(-0.0)));
+				.doubleToLongBits(StrictMath.log1p(0.0)));
+		assertEquals(Double.doubleToLongBits(+0.0), Double
+				.doubleToLongBits(StrictMath.log1p(+0.0)));
+		assertEquals(Double.doubleToLongBits(-0.0), Double
+				.doubleToLongBits(StrictMath.log1p(-0.0)));
 
         assertEquals("Should return -0.2941782295312541", -0.2941782295312541,
                 StrictMath.log1p(-0.254856327));
@@ -792,330 +581,659 @@
     /**
      * @tests java.lang.StrictMath#max(double, double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "max",
-        args = {double.class, double.class}
-    )
-    public void test_maxDD() {
-        // Test for method double java.lang.StrictMath.max(double, double)
-        assertEquals("Incorrect double max value", 1908897.6000089, StrictMath.max(
-                -1908897.6000089, 1908897.6000089), 0D);
-        assertEquals("Incorrect double max value", 1908897.6000089, StrictMath.max(2.0,
-                1908897.6000089), 0D);
-        assertEquals("Incorrect double max value", -2.0, StrictMath.max(-2.0,
-                -1908897.6000089), 0D);
+	public void test_maxDD() {
+		// Test for method double java.lang.StrictMath.max(double, double)
+		assertEquals("Incorrect double max value", 1908897.6000089, StrictMath.max(
+				-1908897.6000089, 1908897.6000089), 0D);
+		assertEquals("Incorrect double max value", 1908897.6000089, StrictMath.max(2.0,
+				1908897.6000089), 0D);
+		assertEquals("Incorrect double max value", -2.0, StrictMath.max(-2.0,
+				-1908897.6000089), 0D);
 
-        assertEquals("Incorrect double max value", Double.NaN, 
-                                               StrictMath.max(Double.NaN, 1.0));
-        assertEquals("Incorrect double max value", 0.0, 
-                                                     StrictMath.max(0.0, -0.0));        
+	}
+
+	/**
+	 * @tests java.lang.StrictMath#max(float, float)
+	 */
+	public void test_maxFF() {
+		// Test for method float java.lang.StrictMath.max(float, float)
+		assertTrue("Incorrect float max value", StrictMath.max(-1908897.600f,
+				1908897.600f) == 1908897.600f);
+		assertTrue("Incorrect float max value", StrictMath.max(2.0f,
+				1908897.600f) == 1908897.600f);
+		assertTrue("Incorrect float max value", StrictMath.max(-2.0f,
+				-1908897.600f) == -2.0f);
+	}
+
+	/**
+	 * @tests java.lang.StrictMath#max(int, int)
+	 */
+	public void test_maxII() {
+		// Test for method int java.lang.StrictMath.max(int, int)
+		assertEquals("Incorrect int max value", 19088976, StrictMath.max(-19088976,
+				19088976));
+		assertEquals("Incorrect int max value",
+				19088976, StrictMath.max(20, 19088976));
+		assertEquals("Incorrect int max value",
+				-20, StrictMath.max(-20, -19088976));
+	}
+
+	/**
+	 * @tests java.lang.StrictMath#max(long, long)
+	 */
+	public void test_maxJJ() {
+		// Test for method long java.lang.StrictMath.max(long, long)
+		assertEquals("Incorrect long max value", 19088976000089L, StrictMath.max(-19088976000089L,
+				19088976000089L));
+		assertEquals("Incorrect long max value", 19088976000089L, StrictMath.max(20,
+				19088976000089L));
+		assertEquals("Incorrect long max value", -20, StrictMath.max(-20,
+				-19088976000089L));
+	}
+
+	/**
+	 * @tests java.lang.StrictMath#min(double, double)
+	 */
+	public void test_minDD() {
+		// Test for method double java.lang.StrictMath.min(double, double)
+		assertEquals("Incorrect double min value", -1908897.6000089, StrictMath.min(
+				-1908897.6000089, 1908897.6000089), 0D);
+		assertEquals("Incorrect double min value", 2.0, StrictMath.min(2.0,
+				1908897.6000089), 0D);
+		assertEquals("Incorrect double min value", -1908897.6000089, StrictMath.min(-2.0,
+				-1908897.6000089), 0D);
+	}
+
+	/**
+	 * @tests java.lang.StrictMath#min(float, float)
+	 */
+	public void test_minFF() {
+		// Test for method float java.lang.StrictMath.min(float, float)
+		assertTrue("Incorrect float min value", StrictMath.min(-1908897.600f,
+				1908897.600f) == -1908897.600f);
+		assertTrue("Incorrect float min value", StrictMath.min(2.0f,
+				1908897.600f) == 2.0f);
+		assertTrue("Incorrect float min value", StrictMath.min(-2.0f,
+				-1908897.600f) == -1908897.600f);
+	}
+
+	/**
+	 * @tests java.lang.StrictMath#min(int, int)
+	 */
+	public void test_minII() {
+		// Test for method int java.lang.StrictMath.min(int, int)
+		assertEquals("Incorrect int min value", -19088976, StrictMath.min(-19088976,
+				19088976));
+		assertEquals("Incorrect int min value",
+				20, StrictMath.min(20, 19088976));
+		assertEquals("Incorrect int min value",
+				-19088976, StrictMath.min(-20, -19088976));
+
+	}
+
+	/**
+	 * @tests java.lang.StrictMath#min(long, long)
+	 */
+	public void test_minJJ() {
+		// Test for method long java.lang.StrictMath.min(long, long)
+		assertEquals("Incorrect long min value", -19088976000089L, StrictMath.min(-19088976000089L,
+				19088976000089L));
+		assertEquals("Incorrect long min value", 20, StrictMath.min(20,
+				19088976000089L));
+		assertEquals("Incorrect long min value", -19088976000089L, StrictMath.min(-20,
+				-19088976000089L));
+	}
+	
+	 /**
+     * @tests {@link java.lang.StrictMath#nextAfter(double, double)}
+     * @since 1.6
+     */
+    @SuppressWarnings("boxing")
+    public void test_nextAfter_DD() {
+        // test for most cases without exception
+        for (int i = 0; i < NEXTAFTER_DD_START_CASES.length; i++) {
+            final double start = NEXTAFTER_DD_START_CASES[i][0];
+            final long nextUpBits = Double
+                    .doubleToLongBits(NEXTAFTER_DD_START_CASES[i][1]);
+            final long nextDownBits = Double
+                    .doubleToLongBits(NEXTAFTER_DD_START_CASES[i][2]);
+
+            for (int j = 0; j < NEXTAFTER_DD_FD_DIRECTION_CASES.length; j++) {
+                final double direction = NEXTAFTER_DD_FD_DIRECTION_CASES[j];
+                final long resultBits = Double.doubleToLongBits(StrictMath
+                        .nextAfter(start, direction));
+                final long directionBits = Double.doubleToLongBits(direction);
+                if (direction > start) {
+                    assertEquals("Result should be next up-number.",
+                            nextUpBits, resultBits);
+                } else if (direction < start) {
+                    assertEquals("Result should be next down-number.",
+                            nextDownBits, resultBits);
+                } else {
+                    assertEquals("Result should be direction.", directionBits,
+                            resultBits);
+                }
+            }
+        }
+
+        // test for cases with NaN
+        for (int i = 0; i < NEXTAFTER_DD_START_CASES.length; i++) {
+            assertTrue("The result should be NaN.", Double.isNaN(StrictMath
+                    .nextAfter(NEXTAFTER_DD_START_CASES[i][0], Double.NaN)));
+        }
+        for (int i = 0; i < NEXTAFTER_DD_FD_DIRECTION_CASES.length; i++) {
+            assertTrue("The result should be NaN.", Double.isNaN(StrictMath
+                    .nextAfter(Double.NaN, NEXTAFTER_DD_FD_DIRECTION_CASES[i])));
+        }
+        assertTrue("The result should be NaN.", Double.isNaN(StrictMath
+                .nextAfter(Double.NaN, Double.NaN)));
+
+        // test for exception
+        try {
+            StrictMath.nextAfter((Double) null, 2.3);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            StrictMath.nextAfter(2.3, (Double) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            StrictMath.nextAfter((Double) null, (Double) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
     }
 
     /**
-     * @tests java.lang.StrictMath#max(float, float)
+     * @tests {@link java.lang.StrictMath#nextAfter(float, double)}
+     * @since 1.6
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "max",
-        args = {float.class, float.class}
-    )
-    public void test_maxFF() {
-        // Test for method float java.lang.StrictMath.max(float, float)
-        assertTrue("Incorrect float max value", StrictMath.max(-1908897.600f,
-                1908897.600f) == 1908897.600f);
-        assertTrue("Incorrect float max value", StrictMath.max(2.0f,
-                1908897.600f) == 1908897.600f);
-        assertTrue("Incorrect float max value", StrictMath.max(-2.0f,
-                -1908897.600f) == -2.0f);
-        assertEquals("Incorrect float max value", Float.NaN, 
-                                                 StrictMath.max(Float.NaN, 1f));
-        assertEquals("Incorrect float max value", 0f, 
-                                                       StrictMath.max(0f, -0f));           
+    @SuppressWarnings("boxing")
+    public void test_nextAfter_FD() {
+        // test for most cases without exception
+        for (int i = 0; i < NEXTAFTER_FD_START_CASES.length; i++) {
+            final float start = NEXTAFTER_FD_START_CASES[i][0];
+            final int nextUpBits = Float
+                    .floatToIntBits(NEXTAFTER_FD_START_CASES[i][1]);
+            final int nextDownBits = Float
+                    .floatToIntBits(NEXTAFTER_FD_START_CASES[i][2]);
+
+            for (int j = 0; j < NEXTAFTER_DD_FD_DIRECTION_CASES.length; j++) {
+                final double direction = NEXTAFTER_DD_FD_DIRECTION_CASES[j];
+                final int resultBits = Float.floatToIntBits(StrictMath
+                        .nextAfter(start, direction));
+                if (direction > start) {
+                    assertEquals("Result should be next up-number.",
+                            nextUpBits, resultBits);
+                } else if (direction < start) {
+                    assertEquals("Result should be next down-number.",
+                            nextDownBits, resultBits);
+                } else {
+                    final int equivalentBits = Float.floatToIntBits(new Float(
+                            direction));
+                    assertEquals(
+                            "Result should be a number equivalent to direction.",
+                            equivalentBits, resultBits);
+                }
+            }
+        }
+
+        // test for cases with NaN
+        for (int i = 0; i < NEXTAFTER_FD_START_CASES.length; i++) {
+            assertTrue("The result should be NaN.", Float.isNaN(StrictMath
+                    .nextAfter(NEXTAFTER_FD_START_CASES[i][0], Float.NaN)));
+        }
+        for (int i = 0; i < NEXTAFTER_DD_FD_DIRECTION_CASES.length; i++) {
+            assertTrue("The result should be NaN.", Float.isNaN(StrictMath
+                    .nextAfter(Float.NaN, NEXTAFTER_DD_FD_DIRECTION_CASES[i])));
+        }
+        assertTrue("The result should be NaN.", Float.isNaN(StrictMath
+                .nextAfter(Float.NaN, Float.NaN)));
+
+        // test for exception
+        try {
+            StrictMath.nextAfter((Float) null, 2.3);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            StrictMath.nextAfter(2.3, (Float) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            StrictMath.nextAfter((Float) null, (Float) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
     }
 
     /**
-     * @tests java.lang.StrictMath#max(int, int)
+     * @tests {@link java.lang.StrictMath#nextUp(double)}
+     * @since 1.6
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "max",
-        args = {int.class, int.class}
-    )
-    public void test_maxII() {
-        // Test for method int java.lang.StrictMath.max(int, int)
-        assertEquals("Incorrect int max value", 19088976, StrictMath.max(-19088976,
-                19088976));
-        assertEquals("Incorrect int max value",
-                19088976, StrictMath.max(20, 19088976));
-        assertEquals("Incorrect int max value",
-                -20, StrictMath.max(-20, -19088976));
-        assertEquals("Returned incorrect value.", Integer.MAX_VALUE, 
-                      StrictMath.max(Integer.MAX_VALUE, 1));  
-        assertEquals("Returned incorrect value.", Integer.MIN_VALUE, 
-                StrictMath.max(Integer.MIN_VALUE, Integer.MIN_VALUE));         
+    @SuppressWarnings("boxing")
+    public void test_nextUp_D() {
+        // This method is semantically equivalent to nextAfter(d,
+        // Double.POSITIVE_INFINITY),
+        // so we use the data of test_nextAfter_DD
+        for (int i = 0; i < NEXTAFTER_DD_START_CASES.length; i++) {
+            final double start = NEXTAFTER_DD_START_CASES[i][0];
+            final long nextUpBits = Double
+                    .doubleToLongBits(NEXTAFTER_DD_START_CASES[i][1]);
+            final long resultBits = Double.doubleToLongBits(StrictMath
+                    .nextUp(start));
+            assertEquals("Result should be next up-number.", nextUpBits,
+                    resultBits);
+        }
+
+        // test for cases with NaN
+        assertTrue("The result should be NaN.", Double.isNaN(StrictMath
+                .nextUp(Double.NaN)));
+
+        // test for exception
+        try {
+            StrictMath.nextUp((Double) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
     }
 
     /**
-     * @tests java.lang.StrictMath#max(long, long)
+     * @tests {@link java.lang.StrictMath#nextUp(float)}
+     * @since 1.6
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "max",
-        args = {long.class, long.class}
-    )
-    public void test_maxJJ() {
-        // Test for method long java.lang.StrictMath.max(long, long)
-        assertEquals("Incorrect long max value", 19088976000089L, StrictMath.max(-19088976000089L,
-                19088976000089L));
-        assertEquals("Incorrect long max value", 19088976000089L, StrictMath.max(20,
-                19088976000089L));
-        assertEquals("Incorrect long max value", -20, StrictMath.max(-20,
-                -19088976000089L));
-        
-        assertEquals("Returned incorrect value.", Long.MAX_VALUE, 
-                StrictMath.max(Long.MAX_VALUE, 1));  
-        assertEquals("Returned incorrect value.", Long.MIN_VALUE, 
-          StrictMath.max(Long.MIN_VALUE, Long.MIN_VALUE));         
+    @SuppressWarnings("boxing")
+    public void test_nextUp_F() {
+        // This method is semantically equivalent to nextAfter(f,
+        // Float.POSITIVE_INFINITY),
+        // so we use the data of test_nextAfter_FD
+        for (int i = 0; i < NEXTAFTER_FD_START_CASES.length; i++) {
+            final float start = NEXTAFTER_FD_START_CASES[i][0];
+            final int nextUpBits = Float
+                    .floatToIntBits(NEXTAFTER_FD_START_CASES[i][1]);
+            final int resultBits = Float.floatToIntBits(StrictMath
+                    .nextUp(start));
+            assertEquals("Result should be next up-number.", nextUpBits,
+                    resultBits);
+        }
+
+        // test for cases with NaN
+        assertTrue("The result should be NaN.", Float.isNaN(StrictMath
+                .nextUp(Float.NaN)));
+
+        // test for exception
+        try {
+            StrictMath.nextUp((Float) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+    }
+
+	/**
+	 * @tests java.lang.StrictMath#pow(double, double)
+	 */
+	public void test_powDD() {
+		// Test for method double java.lang.StrictMath.pow(double, double)
+		assertTrue("pow returned incorrect value",
+				(long) StrictMath.pow(2, 8) == 256l);
+		assertTrue("pow returned incorrect value",
+				StrictMath.pow(2, -8) == 0.00390625d);
+	}
+
+	/**
+	 * @tests java.lang.StrictMath#rint(double)
+	 */
+	public void test_rintD() {
+		// Test for method double java.lang.StrictMath.rint(double)
+		assertEquals("Failed to round properly - up to odd",
+				3.0, StrictMath.rint(2.9), 0D);
+		assertTrue("Failed to round properly - NaN", Double.isNaN(StrictMath
+				.rint(Double.NaN)));
+		assertEquals("Failed to round properly down  to even", 2.0, StrictMath
+				.rint(2.1), 0D);
+		assertTrue("Failed to round properly " + 2.5 + " to even", StrictMath
+				.rint(2.5) == 2.0);
+	}
+
+	/**
+	 * @tests java.lang.StrictMath#round(double)
+	 */
+	public void test_roundD() {
+		// Test for method long java.lang.StrictMath.round(double)
+		assertEquals("Incorrect rounding of a float",
+				-91, StrictMath.round(-90.89d));
+	}
+
+	/**
+	 * @tests java.lang.StrictMath#round(float)
+	 */
+	public void test_roundF() {
+		// Test for method int java.lang.StrictMath.round(float)
+		assertEquals("Incorrect rounding of a float",
+				-91, StrictMath.round(-90.89f));
+	}
+    
+	/**
+     * @tests {@link java.lang.StrictMath#scalb(double, int)}
+     * @since 1.6
+     */
+    @SuppressWarnings("boxing")
+    public void test_scalb_DI() {
+        // result is normal
+        assertEquals(4.1422946304E7, StrictMath.scalb(1.2345, 25));
+        assertEquals(3.679096698760986E-8, StrictMath.scalb(1.2345, -25));
+        assertEquals(1.2345, StrictMath.scalb(1.2345, 0));
+        assertEquals(7868514.304, StrictMath.scalb(0.2345, 25));
+
+        double normal = StrictMath.scalb(0.2345, -25);
+        assertEquals(6.98864459991455E-9, normal);
+        // precision kept
+        assertEquals(0.2345, StrictMath.scalb(normal, 25));
+
+        assertEquals(0.2345, StrictMath.scalb(0.2345, 0));
+        assertEquals(-4.1422946304E7, StrictMath.scalb(-1.2345, 25));
+        assertEquals(-6.98864459991455E-9, StrictMath.scalb(-0.2345, -25));
+        assertEquals(2.0, StrictMath.scalb(Double.MIN_NORMAL / 2, 1024));
+        assertEquals(64.0, StrictMath.scalb(Double.MIN_VALUE, 1080));
+        assertEquals(234, StrictMath.getExponent(StrictMath.scalb(1.0, 234)));
+        assertEquals(3.9999999999999996, StrictMath.scalb(Double.MAX_VALUE,
+                Double.MIN_EXPONENT));
+
+        // result is near infinity
+        double halfMax = StrictMath.scalb(1.0, Double.MAX_EXPONENT);
+        assertEquals(8.98846567431158E307, halfMax);
+        assertEquals(Double.MAX_VALUE, halfMax - StrictMath.ulp(halfMax)
+                + halfMax);
+        assertEquals(Double.POSITIVE_INFINITY, halfMax + halfMax);
+        assertEquals(1.7976931348623155E308, StrictMath.scalb(1.0 - StrictMath
+                .ulp(1.0), Double.MAX_EXPONENT + 1));
+        assertEquals(Double.POSITIVE_INFINITY, StrictMath.scalb(
+                1.0 - StrictMath.ulp(1.0), Double.MAX_EXPONENT + 2));
+
+        halfMax = StrictMath.scalb(-1.0, Double.MAX_EXPONENT);
+        assertEquals(-8.98846567431158E307, halfMax);
+        assertEquals(-Double.MAX_VALUE, halfMax + StrictMath.ulp(halfMax)
+                + halfMax);
+        assertEquals(Double.NEGATIVE_INFINITY, halfMax + halfMax);
+
+        assertEquals(Double.POSITIVE_INFINITY, StrictMath.scalb(0.345, 1234));
+        assertEquals(Double.POSITIVE_INFINITY, StrictMath
+                .scalb(44.345E102, 934));
+        assertEquals(Double.NEGATIVE_INFINITY, StrictMath.scalb(-44.345E102,
+                934));
+
+        assertEquals(Double.POSITIVE_INFINITY, StrictMath.scalb(
+                Double.MIN_NORMAL / 2, 4000));
+        assertEquals(Double.POSITIVE_INFINITY, StrictMath.scalb(
+                Double.MIN_VALUE, 8000));
+        assertEquals(Double.POSITIVE_INFINITY, StrictMath.scalb(
+                Double.MAX_VALUE, 1));
+        assertEquals(Double.POSITIVE_INFINITY, StrictMath.scalb(
+                Double.POSITIVE_INFINITY, 0));
+        assertEquals(Double.POSITIVE_INFINITY, StrictMath.scalb(
+                Double.POSITIVE_INFINITY, -1));
+        assertEquals(Double.NEGATIVE_INFINITY, StrictMath.scalb(
+                Double.NEGATIVE_INFINITY, -1));
+        assertEquals(Double.NEGATIVE_INFINITY, StrictMath.scalb(
+                Double.NEGATIVE_INFINITY, Double.MIN_EXPONENT));
+
+        // result is subnormal/zero
+        long posZeroBits = Double.doubleToLongBits(+0.0);
+        long negZeroBits = Double.doubleToLongBits(-0.0);
+        assertEquals(posZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                +0.0, Integer.MAX_VALUE)));
+        assertEquals(posZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                +0.0, -123)));
+        assertEquals(posZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                +0.0, 0)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                -0.0, 123)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                -0.0, Integer.MIN_VALUE)));
+
+        assertEquals(Double.MIN_VALUE, StrictMath.scalb(1.0, -1074));
+        assertEquals(posZeroBits, Double.doubleToLongBits(StrictMath.scalb(1.0,
+                -1075)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                -1.0, -1075)));
+
+        // precision lost
+        assertEquals(StrictMath.scalb(21.405, -1078), StrictMath.scalb(21.405,
+                -1079));
+        assertEquals(Double.MIN_VALUE, StrictMath.scalb(21.405, -1079));
+        assertEquals(-Double.MIN_VALUE, StrictMath.scalb(-21.405, -1079));
+        assertEquals(posZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                21.405, -1080)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                -21.405, -1080)));
+        assertEquals(posZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                Double.MIN_VALUE, -1)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                -Double.MIN_VALUE, -1)));
+        assertEquals(Double.MIN_VALUE, StrictMath.scalb(Double.MIN_NORMAL, -52));
+        assertEquals(posZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                Double.MIN_NORMAL, -53)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                -Double.MIN_NORMAL, -53)));
+        assertEquals(Double.MIN_VALUE, StrictMath
+                .scalb(Double.MAX_VALUE, -2098));
+        assertEquals(posZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                Double.MAX_VALUE, -2099)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                -Double.MAX_VALUE, -2099)));
+        assertEquals(Double.MIN_VALUE, StrictMath.scalb(Double.MIN_NORMAL / 3,
+                -51));
+        assertEquals(posZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                Double.MIN_NORMAL / 3, -52)));
+        assertEquals(negZeroBits, Double.doubleToLongBits(StrictMath.scalb(
+                -Double.MIN_NORMAL / 3, -52)));
+        double subnormal = StrictMath.scalb(Double.MIN_NORMAL / 3, -25);
+        assertEquals(2.2104123E-316, subnormal);
+        // precision lost
+        assertFalse(Double.MIN_NORMAL / 3 == StrictMath.scalb(subnormal, 25));
+
+        // NaN
+        assertTrue(Double.isNaN(StrictMath.scalb(Double.NaN, 1)));
+        assertTrue(Double.isNaN(StrictMath.scalb(Double.NaN, 0)));
+        assertTrue(Double.isNaN(StrictMath.scalb(Double.NaN, -120)));
+
+        assertEquals(1283457024, Double.doubleToLongBits(StrictMath.scalb(
+                Double.MIN_VALUE * 153, 23)));
+        assertEquals(-9223372035571318784L, Double.doubleToLongBits(StrictMath
+                .scalb(-Double.MIN_VALUE * 153, 23)));
+        assertEquals(36908406321184768L, Double.doubleToLongBits(StrictMath
+                .scalb(Double.MIN_VALUE * 153, 52)));
+        assertEquals(-9186463630533591040L, Double.doubleToLongBits(StrictMath
+                .scalb(-Double.MIN_VALUE * 153, 52)));
+
+        // test for exception
+        try {
+            StrictMath.scalb((Double) null, (Integer) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            StrictMath.scalb(1.0, (Integer) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            StrictMath.scalb((Double) null, 1);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
     }
 
     /**
-     * @tests java.lang.StrictMath#min(double, double)
+     * @tests {@link java.lang.StrictMath#scalb(float, int)}
+     * @since 1.6
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "min",
-        args = {double.class, double.class}
-    )
-    public void test_minDD() {
-        // Test for method double java.lang.StrictMath.min(double, double)
-        assertEquals("Incorrect double min value", -1908897.6000089, StrictMath.min(
-                -1908897.6000089, 1908897.6000089), 0D);
-        assertEquals("Incorrect double min value", 2.0, StrictMath.min(2.0,
-                1908897.6000089), 0D);
-        assertEquals("Incorrect double min value", -1908897.6000089, StrictMath.min(-2.0,
-                -1908897.6000089), 0D);
-        assertEquals("Returned incorrect value.", Double.NaN, 
-                                               StrictMath.min(Double.NaN, 1.0));
-        assertEquals("Returned incorrect value.", Double.NaN, 
-                                               StrictMath.min(1.0, Double.NaN));      
-        assertEquals("Returned incorrect value.", -0.0, StrictMath.min(0.0, -0.0));  
-    }
+    @SuppressWarnings("boxing")
+    public void test_scalb_FI() {
+        // result is normal
+        assertEquals(4.1422946304E7f, StrictMath.scalb(1.2345f, 25));
+        assertEquals(3.679096698760986E-8f, StrictMath.scalb(1.2345f, -25));
+        assertEquals(1.2345f, StrictMath.scalb(1.2345f, 0));
+        assertEquals(7868514.304f, StrictMath.scalb(0.2345f, 25));
 
-    /**
-     * @tests java.lang.StrictMath#min(float, float)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "min",
-        args = {float.class, float.class}
-    )
-    public void test_minFF() {
-        // Test for method float java.lang.StrictMath.min(float, float)
-        assertTrue("Incorrect float min value", StrictMath.min(-1908897.600f,
-                1908897.600f) == -1908897.600f);
-        assertTrue("Incorrect float min value", StrictMath.min(2.0f,
-                1908897.600f) == 2.0f);
-        assertTrue("Incorrect float min value", StrictMath.min(-2.0f,
-                -1908897.600f) == -1908897.600f);
-        
-        assertEquals("Returned incorrect value.", Float.NaN, 
-                StrictMath.min(Float.NaN, 1f));
-        assertEquals("Returned incorrect value.", Float.NaN, 
-                StrictMath.min(1f, Float.NaN));      
-        assertEquals("Returned incorrect value.", -0f, StrictMath.min(0f, -0f));  
-    }
+        float normal = StrictMath.scalb(0.2345f, -25);
+        assertEquals(6.98864459991455E-9f, normal);
+        // precision kept
+        assertEquals(0.2345f, StrictMath.scalb(normal, 25));
 
-    /**
-     * @tests java.lang.StrictMath#min(int, int)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "min",
-        args = {int.class, int.class}
-    )
-    public void test_minII() {
-        // Test for method int java.lang.StrictMath.min(int, int)
-        assertEquals("Incorrect int min value", -19088976, StrictMath.min(-19088976,
-                19088976));
-        assertEquals("Incorrect int min value",
-                20, StrictMath.min(20, 19088976));
-        assertEquals("Incorrect int min value",
-                -19088976, StrictMath.min(-20, -19088976));
+        assertEquals(0.2345f, StrictMath.scalb(0.2345f, 0));
+        assertEquals(-4.1422946304E7f, StrictMath.scalb(-1.2345f, 25));
+        assertEquals(-6.98864459991455E-9f, StrictMath.scalb(-0.2345f, -25));
+        assertEquals(2.0f, StrictMath.scalb(Float.MIN_NORMAL / 2, 128));
+        assertEquals(64.0f, StrictMath.scalb(Float.MIN_VALUE, 155));
+        assertEquals(34, StrictMath.getExponent(StrictMath.scalb(1.0f, 34)));
+        assertEquals(3.9999998f, StrictMath.scalb(Float.MAX_VALUE,
+                Float.MIN_EXPONENT));
 
-        assertEquals("Incorrect value was returned.", Double.MIN_VALUE, 
-                StrictMath.min(Double.MIN_VALUE, Double.MIN_VALUE));
-    }
+        // result is near infinity
+        float halfMax = StrictMath.scalb(1.0f, Float.MAX_EXPONENT);
+        assertEquals(1.7014118E38f, halfMax);
+        assertEquals(Float.MAX_VALUE, halfMax - StrictMath.ulp(halfMax)
+                + halfMax);
+        assertEquals(Float.POSITIVE_INFINITY, halfMax + halfMax);
+        assertEquals(3.4028233E38f, StrictMath.scalb(1.0f - StrictMath
+                .ulp(1.0f), Float.MAX_EXPONENT + 1));
+        assertEquals(Float.POSITIVE_INFINITY, StrictMath.scalb(
+                1.0f - StrictMath.ulp(1.0f), Float.MAX_EXPONENT + 2));
 
-    /**
-     * @tests java.lang.StrictMath#min(long, long)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "min",
-        args = {long.class, long.class}
-    )
-    public void test_minJJ() {
-        // Test for method long java.lang.StrictMath.min(long, long)
-        assertEquals("Incorrect long min value", -19088976000089L, StrictMath.min(-19088976000089L,
-                19088976000089L));
-        assertEquals("Incorrect long min value", 20, StrictMath.min(20,
-                19088976000089L));
-        assertEquals("Incorrect long min value", -19088976000089L, StrictMath.min(-20,
-                -19088976000089L));
-        assertEquals("Incorrect value was returned.", Long.MIN_VALUE, 
-                StrictMath.min(Long.MIN_VALUE, Long.MIN_VALUE));        
-    }
+        halfMax = StrictMath.scalb(-1.0f, Float.MAX_EXPONENT);
+        assertEquals(-1.7014118E38f, halfMax);
+        assertEquals(-Float.MAX_VALUE, halfMax + StrictMath.ulp(halfMax)
+                + halfMax);
+        assertEquals(Float.NEGATIVE_INFINITY, halfMax + halfMax);
 
-    /**
-     * @tests java.lang.StrictMath#pow(double, double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "pow",
-        args = {double.class, double.class}
-    )
-    public void test_powDD() {
-        // Test for method double java.lang.StrictMath.pow(double, double)
-        assertTrue("pow returned incorrect value",
-                (long) StrictMath.pow(2, 8) == 256l);
-        assertTrue("pow returned incorrect value",
-                StrictMath.pow(2, -8) == 0.00390625d);
-        
-        assertEquals(1.0, StrictMath.pow(1.0, 0.0));
-        assertEquals(1.0, StrictMath.pow(1.0, -0.0));
-        
-        assertEquals(Double.NaN, StrictMath.pow(1.0, Double.NaN));
-        assertEquals(Double.NaN, StrictMath.pow(Double.NaN, 1.0));  
-        
-        assertEquals(Double.POSITIVE_INFINITY, 
-                StrictMath.pow(1.1, Double.POSITIVE_INFINITY));
-        assertEquals(Double.POSITIVE_INFINITY, 
-                StrictMath.pow(0.1, Double.NEGATIVE_INFINITY));  
-        
-        assertEquals(0.0, StrictMath.pow(1.1, Double.NEGATIVE_INFINITY));
-        assertEquals(0.0, StrictMath.pow(0.1, Double.POSITIVE_INFINITY));
-        
-        assertEquals(Double.NaN, StrictMath.pow(1.0, Double.NEGATIVE_INFINITY));
-        assertEquals(Double.NaN, StrictMath.pow(1.0, Double.POSITIVE_INFINITY));
+        assertEquals(Float.POSITIVE_INFINITY, StrictMath.scalb(0.345f, 1234));
+        assertEquals(Float.POSITIVE_INFINITY, StrictMath.scalb(44.345E10f, 934));
+        assertEquals(Float.NEGATIVE_INFINITY, StrictMath
+                .scalb(-44.345E10f, 934));
 
-        assertEquals(0.0, StrictMath.pow(0.0, 1.0));
-        assertEquals(0.0, StrictMath.pow(Double.POSITIVE_INFINITY, -1.0));
-        
-        assertEquals(Double.POSITIVE_INFINITY, StrictMath.pow(0.0, -1.0));
-        assertEquals(Double.POSITIVE_INFINITY, 
-                StrictMath.pow(Double.POSITIVE_INFINITY, 1.0));
-        
-        assertEquals(0.0, StrictMath.pow(-0.0, 2.0));
-        assertEquals(0.0, StrictMath.pow(Double.NEGATIVE_INFINITY, -2.0));
-        
-        assertEquals(Double.POSITIVE_INFINITY, StrictMath.pow(-0.0, -2.0));
-        assertEquals(Double.POSITIVE_INFINITY, StrictMath.pow(
-                Double.NEGATIVE_INFINITY, 2.0)); 
-        
-        assertEquals(Double.NEGATIVE_INFINITY, StrictMath.pow(-0.0, -1.0));
-        assertEquals(Double.NEGATIVE_INFINITY, StrictMath.pow(
-                Double.NEGATIVE_INFINITY, 1.0));         
-        
-        assertEquals(Double.NaN, StrictMath.pow(-1.0, 1.1));       
-    }
+        assertEquals(Float.POSITIVE_INFINITY, StrictMath.scalb(
+                Float.MIN_NORMAL / 2, 400));
+        assertEquals(Float.POSITIVE_INFINITY, StrictMath.scalb(Float.MIN_VALUE,
+                800));
+        assertEquals(Float.POSITIVE_INFINITY, StrictMath.scalb(Float.MAX_VALUE,
+                1));
+        assertEquals(Float.POSITIVE_INFINITY, StrictMath.scalb(
+                Float.POSITIVE_INFINITY, 0));
+        assertEquals(Float.POSITIVE_INFINITY, StrictMath.scalb(
+                Float.POSITIVE_INFINITY, -1));
+        assertEquals(Float.NEGATIVE_INFINITY, StrictMath.scalb(
+                Float.NEGATIVE_INFINITY, -1));
+        assertEquals(Float.NEGATIVE_INFINITY, StrictMath.scalb(
+                Float.NEGATIVE_INFINITY, Float.MIN_EXPONENT));
 
-    /**
-     * @tests java.lang.StrictMath#rint(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "rint",
-        args = {double.class}
-    )
-    public void test_rintD() {
-        // Test for method double java.lang.StrictMath.rint(double)
-        assertEquals("Failed to round properly - up to odd",
-                3.0, StrictMath.rint(2.9), 0D);
-        assertTrue("Failed to round properly - NaN", Double.isNaN(StrictMath
-                .rint(Double.NaN)));
-        assertEquals("Failed to round properly down  to even", 2.0, StrictMath
-                .rint(2.1), 0D);
-        assertTrue("Failed to round properly " + 2.5 + " to even", StrictMath
-                .rint(2.5) == 2.0);
-    }
+        // result is subnormal/zero
+        int posZeroBits = Float.floatToIntBits(+0.0f);
+        int negZeroBits = Float.floatToIntBits(-0.0f);
+        assertEquals(posZeroBits, Float.floatToIntBits(StrictMath.scalb(+0.0f,
+                Integer.MAX_VALUE)));
+        assertEquals(posZeroBits, Float.floatToIntBits(StrictMath.scalb(+0.0f,
+                -123)));
+        assertEquals(posZeroBits, Float.floatToIntBits(StrictMath.scalb(+0.0f,
+                0)));
+        assertEquals(negZeroBits, Float.floatToIntBits(StrictMath.scalb(-0.0f,
+                123)));
+        assertEquals(negZeroBits, Float.floatToIntBits(StrictMath.scalb(-0.0f,
+                Integer.MIN_VALUE)));
 
-    /**
-     * @tests java.lang.StrictMath#round(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "round",
-        args = {double.class}
-    )
-    public void test_roundD() {
-        // Test for method long java.lang.StrictMath.round(double)
-        assertEquals("Incorrect rounding of a float",
-                -91, StrictMath.round(-90.89d));
-        
-        assertEquals("Incorrect rounding of NaN", 0l, 
-                                                  StrictMath.round(Double.NaN));
-        assertEquals("Incorrect rounding of NEGATIVE_INFINITY", Long.MIN_VALUE, 
-                                    StrictMath.round(Double.NEGATIVE_INFINITY));
-        assertEquals("Incorrect rounding of value less than Long.MIN_VALUE", 
-            Long.MIN_VALUE, StrictMath.round(new Double(Long.MIN_VALUE - 0.1)));   
-        assertEquals("Incorrect rounding of Long.MIN_VALUE", 
-                Long.MIN_VALUE, StrictMath.round(new Double(Long.MIN_VALUE))); 
-        assertEquals("Incorrect rounding of Long.MAX_VALUE", 
-                Long.MAX_VALUE, StrictMath.round(Double.POSITIVE_INFINITY));  
-        assertEquals("Incorrect rounding of value greater than Long.MAX_VALUE", 
-            Long.MAX_VALUE, StrictMath.round(new Double(Long.MAX_VALUE + 0.1)));        
-        
-    }
+        assertEquals(Float.MIN_VALUE, StrictMath.scalb(1.0f, -149));
+        assertEquals(posZeroBits, Float.floatToIntBits(StrictMath.scalb(1.0f,
+                -150)));
+        assertEquals(negZeroBits, Float.floatToIntBits(StrictMath.scalb(-1.0f,
+                -150)));
 
-    /**
-     * @tests java.lang.StrictMath#round(float)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "round",
-        args = {float.class}
-    )
-    public void test_roundF() {
-        // Test for method int java.lang.StrictMath.round(float)
-        assertEquals("Incorrect rounding of a float",
-                -91, StrictMath.round(-90.89f));
-        
-        assertEquals("Incorrect rounding of NaN", 0l, 
-                        StrictMath.round(Float.NaN));
-        assertEquals("Incorrect rounding of NEGATIVE_INFINITY", 
-                  Integer.MIN_VALUE, StrictMath.round(Float.NEGATIVE_INFINITY));
-        assertEquals("Incorrect rounding of value less than Integer.MIN_VALUE", 
-        Integer.MIN_VALUE, StrictMath.round(new Float(Integer.MIN_VALUE - 0.1)));   
-        assertEquals("Incorrect rounding of Integer.MIN_VALUE", 
-        Integer.MIN_VALUE, StrictMath.round(new Float(Integer.MIN_VALUE))); 
-        assertEquals("Incorrect rounding of Integer.MAX_VALUE", 
-        Integer.MAX_VALUE, StrictMath.round(Float.POSITIVE_INFINITY));  
-        assertEquals("Incorrect rounding of value greater than Integer.MAX_VALUE", 
-        Integer.MAX_VALUE, StrictMath.round(new Float(Integer.MAX_VALUE + 0.1)));
+        // precision lost
+        assertEquals(StrictMath.scalb(21.405f, -154), StrictMath.scalb(21.405f,
+                -153));
+        assertEquals(Float.MIN_VALUE, StrictMath.scalb(21.405f, -154));
+        assertEquals(-Float.MIN_VALUE, StrictMath.scalb(-21.405f, -154));
+        assertEquals(posZeroBits, Float.floatToIntBits(StrictMath.scalb(
+                21.405f, -155)));
+        assertEquals(negZeroBits, Float.floatToIntBits(StrictMath.scalb(
+                -21.405f, -155)));
+        assertEquals(posZeroBits, Float.floatToIntBits(StrictMath.scalb(
+                Float.MIN_VALUE, -1)));
+        assertEquals(negZeroBits, Float.floatToIntBits(StrictMath.scalb(
+                -Float.MIN_VALUE, -1)));
+        assertEquals(Float.MIN_VALUE, StrictMath.scalb(Float.MIN_NORMAL, -23));
+        assertEquals(posZeroBits, Float.floatToIntBits(StrictMath.scalb(
+                Float.MIN_NORMAL, -24)));
+        assertEquals(negZeroBits, Float.floatToIntBits(StrictMath.scalb(
+                -Float.MIN_NORMAL, -24)));
+        assertEquals(Float.MIN_VALUE, StrictMath.scalb(Float.MAX_VALUE, -277));
+        assertEquals(posZeroBits, Float.floatToIntBits(StrictMath.scalb(
+                Float.MAX_VALUE, -278)));
+        assertEquals(negZeroBits, Float.floatToIntBits(StrictMath.scalb(
+                -Float.MAX_VALUE, -278)));
+        assertEquals(Float.MIN_VALUE, StrictMath.scalb(Float.MIN_NORMAL / 3,
+                -22));
+        assertEquals(posZeroBits, Float.floatToIntBits(StrictMath.scalb(
+                Float.MIN_NORMAL / 3, -23)));
+        assertEquals(negZeroBits, Float.floatToIntBits(StrictMath.scalb(
+                -Float.MIN_NORMAL / 3, -23)));
+        float subnormal = StrictMath.scalb(Float.MIN_NORMAL / 3, -11);
+        assertEquals(1.913E-42f, subnormal);
+        // precision lost
+        assertFalse(Float.MIN_NORMAL / 3 == StrictMath.scalb(subnormal, 11));
+
+        assertEquals(68747264, Float.floatToIntBits(StrictMath.scalb(
+                Float.MIN_VALUE * 153, 23)));
+        assertEquals(-2078736384, Float.floatToIntBits(StrictMath.scalb(
+                -Float.MIN_VALUE * 153, 23)));
+
+        assertEquals(4896, Float.floatToIntBits(StrictMath.scalb(
+                Float.MIN_VALUE * 153, 5)));
+        assertEquals(-2147478752, Float.floatToIntBits(StrictMath.scalb(
+                -Float.MIN_VALUE * 153, 5)));
+
+        // NaN
+        assertTrue(Float.isNaN(StrictMath.scalb(Float.NaN, 1)));
+        assertTrue(Float.isNaN(StrictMath.scalb(Float.NaN, 0)));
+        assertTrue(Float.isNaN(StrictMath.scalb(Float.NaN, -120)));
+
+        // test for exception
+        try {
+            StrictMath.scalb((Float) null, (Integer) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            StrictMath.scalb(1.0f, (Integer) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        try {
+            StrictMath.scalb((Float) null, 1);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
     }
     
     /**
      * @tests java.lang.StrictMath#signum(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "signum",
-        args = {double.class}
-    )
     public void test_signum_D() {
         assertTrue(Double.isNaN(StrictMath.signum(Double.NaN)));
         assertEquals(Double.doubleToLongBits(0.0), Double
@@ -1142,12 +1260,6 @@
     /**
      * @tests java.lang.StrictMath#signum(float)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "signum",
-        args = {float.class}
-    )
     public void test_signum_F() {
         assertTrue(Float.isNaN(StrictMath.signum(Float.NaN)));
         assertEquals(Float.floatToIntBits(0.0f), Float
@@ -1170,44 +1282,18 @@
         assertEquals(-1.0f, StrictMath.signum(Float.NEGATIVE_INFINITY), 0f);
     }
 
-    /**
+	/**
      * @tests java.lang.StrictMath#sin(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "sin",
-        args = {double.class}
-    )
-    public void test_sinD() {
-        // Test for method double java.lang.StrictMath.sin(double)
-        assertTrue("Returned incorrect sine", StrictMath.sin(StrictMath
-                .asin(OPP / HYP)) == OPP / HYP);
-        
-        assertEquals("Returned incorrect sin value.", 
-                Double.NaN, StrictMath.sin(Double.NaN));
-        
-        assertEquals("Returned incorrect sin value.", 
-                Double.NaN, StrictMath.sin(Double.POSITIVE_INFINITY));
-        
-        assertEquals("Returned incorrect sin value.", 
-                Double.NaN, StrictMath.sin(Double.NEGATIVE_INFINITY));   
-        
-        assertEquals("Returned incorrect sin value.", 
-                0.0, StrictMath.sin(0.0));   
-        assertEquals("Returned incorrect sin value.", 
-                -0.0, StrictMath.sin(-0.0));        
-    }
+	public void test_sinD() {
+		// Test for method double java.lang.StrictMath.sin(double)
+		assertTrue("Returned incorrect sine", StrictMath.sin(StrictMath
+				.asin(OPP / HYP)) == OPP / HYP);
+	}
 
     /**
      * @tests java.lang.StrictMath#sinh(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "sinh",
-        args = {double.class}
-    )
     public void test_sinh_D() {
         // Test for special situations
         assertTrue(Double.isNaN(StrictMath.sinh(Double.NaN)));
@@ -1218,11 +1304,11 @@
                 Double.NEGATIVE_INFINITY, StrictMath
                         .sinh(Double.NEGATIVE_INFINITY), 0D);
         assertEquals(Double.doubleToLongBits(0.0), Double
-                .doubleToLongBits(StrictMath.sinh(0.0)));
-        assertEquals(Double.doubleToLongBits(+0.0), Double
-                .doubleToLongBits(StrictMath.sinh(+0.0)));
-        assertEquals(Double.doubleToLongBits(-0.0), Double
-                .doubleToLongBits(StrictMath.sinh(-0.0)));
+				.doubleToLongBits(StrictMath.sinh(0.0)));
+		assertEquals(Double.doubleToLongBits(+0.0), Double
+				.doubleToLongBits(StrictMath.sinh(+0.0)));
+		assertEquals(Double.doubleToLongBits(-0.0), Double
+				.doubleToLongBits(StrictMath.sinh(-0.0)));
 
         assertEquals("Should return POSITIVE_INFINITY",
                 Double.POSITIVE_INFINITY, StrictMath.sinh(1234.56), 0D);
@@ -1240,58 +1326,30 @@
                 .sinh(Double.MIN_VALUE), 0D);
     }
     
-    /**
-     * @tests java.lang.StrictMath#sqrt(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "sqrt",
-        args = {double.class}
-    )
-    public void test_sqrtD() {
-        // Test for method double java.lang.StrictMath.sqrt(double)
-        assertEquals("Incorrect root returned1",
+	/**
+	 * @tests java.lang.StrictMath#sqrt(double)
+	 */
+	public void test_sqrtD() {
+		// Test for method double java.lang.StrictMath.sqrt(double)
+		assertEquals("Incorrect root returned1",
                              2, StrictMath.sqrt(StrictMath.pow(StrictMath.sqrt(2), 4)), 0.0);
-        assertEquals("Incorrect root returned2", 7, StrictMath.sqrt(49), 0.0);
-        
-        assertEquals("Incorrect root was returned.", Double.NaN, 
-                StrictMath.sqrt(Double.NaN));
-        assertEquals("Incorrect root was returned.", Double.NaN, 
-                StrictMath.sqrt(-0.1));        
-        assertEquals("Incorrect root was returned.", Double.POSITIVE_INFINITY, 
-                StrictMath.sqrt(Double.POSITIVE_INFINITY)); 
-        
-        assertEquals("Incorrect root was returned.", 0.0, StrictMath.sqrt(0.0));     
-        assertEquals("Incorrect root was returned.", -0.0, StrictMath.sqrt(-0.0));       
-    }
+		assertEquals("Incorrect root returned2", 7, StrictMath.sqrt(49), 0.0);
+	}
 
-    /**
-     * @tests java.lang.StrictMath#tan(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.PARTIAL,
-        notes = "Doesn't check boundary values.",
-        method = "tan",
-        args = {double.class}
-    )
-    public void test_tanD() {
-        // Test for method double java.lang.StrictMath.tan(double)
-        assertTrue(
-                "Returned incorrect tangent: ",
-                StrictMath.tan(StrictMath.atan(1.0)) <= 1.0
-                        || StrictMath.tan(StrictMath.atan(1.0)) >= 9.9999999999999983E-1);
-    }
+	/**
+	 * @tests java.lang.StrictMath#tan(double)
+	 */
+	public void test_tanD() {
+		// Test for method double java.lang.StrictMath.tan(double)
+		assertTrue(
+				"Returned incorrect tangent: ",
+				StrictMath.tan(StrictMath.atan(1.0)) <= 1.0
+						|| StrictMath.tan(StrictMath.atan(1.0)) >= 9.9999999999999983E-1);
+	}
 
     /**
      * @tests java.lang.StrictMath#tanh(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "tanh",
-        args = {double.class}
-    )
     public void test_tanh_D() {
         // Test for special situations
         assertTrue(Double.isNaN(StrictMath.tanh(Double.NaN)));
@@ -1300,11 +1358,11 @@
         assertEquals("Should return -1.0", -1.0, StrictMath
                 .tanh(Double.NEGATIVE_INFINITY), 0D);
         assertEquals(Double.doubleToLongBits(0.0), Double
-                .doubleToLongBits(StrictMath.tanh(0.0)));
-        assertEquals(Double.doubleToLongBits(+0.0), Double
-                .doubleToLongBits(StrictMath.tanh(+0.0)));
-        assertEquals(Double.doubleToLongBits(-0.0), Double
-                .doubleToLongBits(StrictMath.tanh(-0.0)));
+				.doubleToLongBits(StrictMath.tanh(0.0)));
+		assertEquals(Double.doubleToLongBits(+0.0), Double
+				.doubleToLongBits(StrictMath.tanh(+0.0)));
+		assertEquals(Double.doubleToLongBits(-0.0), Double
+				.doubleToLongBits(StrictMath.tanh(-0.0)));
 
         assertEquals("Should return 1.0", 1.0, StrictMath.tanh(1234.56), 0D);
         assertEquals("Should return -1.0", -1.0, StrictMath.tanh(-1234.56), 0D);
@@ -1318,172 +1376,115 @@
                 .tanh(Double.MIN_VALUE), 0D);
     }
     
-    /**
-     * @tests java.lang.StrictMath#random()
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "random",
-        args = {}
-    )
-    public void test_random() {
-        // There isn't a place for these tests so just stick them here
-        assertEquals("Wrong value E",
-                4613303445314885481L, Double.doubleToLongBits(StrictMath.E));
-        assertEquals("Wrong value PI",
-                4614256656552045848L, Double.doubleToLongBits(StrictMath.PI));
+	/**
+	 * @tests java.lang.StrictMath#random()
+	 */
+	public void test_random() {
+		// There isn't a place for these tests so just stick them here
+		assertEquals("Wrong value E",
+				4613303445314885481L, Double.doubleToLongBits(StrictMath.E));
+		assertEquals("Wrong value PI",
+				4614256656552045848L, Double.doubleToLongBits(StrictMath.PI));
 
-        for (int i = 500; i >= 0; i--) {
-            double d = StrictMath.random();
-            assertTrue("Generated number is out of range: " + d, d >= 0.0
-                    && d < 1.0);
-        }
-    }
+		for (int i = 500; i >= 0; i--) {
+			double d = StrictMath.random();
+			assertTrue("Generated number is out of range: " + d, d >= 0.0
+					&& d < 1.0);
+		}
+	}
 
-    /**
-     * @tests java.lang.StrictMath#toRadians(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "toRadians",
-        args = {double.class}
-    )
-    public void test_toRadiansD() {
-        for (double d = 500; d >= 0; d -= 1.0) {
-            double converted = StrictMath.toDegrees(StrictMath.toRadians(d));
-            assertTrue("Converted number not equal to original. d = " + d,
-                    converted >= d * 0.99999999 && converted <= d * 1.00000001);
-        }
-    }
+	/**
+	 * @tests java.lang.StrictMath#toRadians(double)
+	 */
+	public void test_toRadiansD() {
+		for (double d = 500; d >= 0; d -= 1.0) {
+			double converted = StrictMath.toDegrees(StrictMath.toRadians(d));
+			assertTrue("Converted number not equal to original. d = " + d,
+					converted >= d * 0.99999999 && converted <= d * 1.00000001);
+		}
+	}
 
-    /**
-     * @tests java.lang.StrictMath#toDegrees(double)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "toDegrees",
-        args = {double.class}
-    )
-    public void test_toDegreesD() {
-        for (double d = 500; d >= 0; d -= 1.0) {
-            double converted = StrictMath.toRadians(StrictMath.toDegrees(d));
-            assertTrue("Converted number not equal to original. d = " + d,
-                    converted >= d * 0.99999999 && converted <= d * 1.00000001);
-        }
-    }
-    
-    /**
+	/**
+	 * @tests java.lang.StrictMath#toDegrees(double)
+	 */
+	public void test_toDegreesD() {
+		for (double d = 500; d >= 0; d -= 1.0) {
+			double converted = StrictMath.toRadians(StrictMath.toDegrees(d));
+			assertTrue("Converted number not equal to original. d = " + d,
+					converted >= d * 0.99999999 && converted <= d * 1.00000001);
+		}
+	}
+	
+	/**
      * @tests java.lang.StrictMath#ulp(double)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "ulp",
-        args = {double.class}
-    )
      @SuppressWarnings("boxing")
     public void test_ulp_D() {
         // Test for special cases
-        assertTrue("Should return NaN", Double
-                .isNaN(StrictMath.ulp(Double.NaN)));
-        assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY,
-                StrictMath.ulp(Double.POSITIVE_INFINITY), 0D);
-        assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY,
-                StrictMath.ulp(Double.NEGATIVE_INFINITY), 0D);
-        assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
-                .ulp(0.0), 0D);
-        assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
-                .ulp(+0.0), 0D);
-        assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
-                .ulp(-0.0), 0D);
-        assertEquals("Returned incorrect value", StrictMath.pow(2, 971),
-                StrictMath.ulp(Double.MAX_VALUE), 0D);
-        assertEquals("Returned incorrect value", StrictMath.pow(2, 971),
-                StrictMath.ulp(-Double.MAX_VALUE), 0D);
+		assertTrue("Should return NaN", Double
+				.isNaN(StrictMath.ulp(Double.NaN)));
+		assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY,
+				StrictMath.ulp(Double.POSITIVE_INFINITY), 0D);
+		assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY,
+				StrictMath.ulp(Double.NEGATIVE_INFINITY), 0D);
+		assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+				.ulp(0.0), 0D);
+		assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+				.ulp(+0.0), 0D);
+		assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+				.ulp(-0.0), 0D);
+		assertEquals("Returned incorrect value", StrictMath.pow(2, 971),
+				StrictMath.ulp(Double.MAX_VALUE), 0D);
+		assertEquals("Returned incorrect value", StrictMath.pow(2, 971),
+				StrictMath.ulp(-Double.MAX_VALUE), 0D);
 
-        assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
-                .ulp(Double.MIN_VALUE), 0D);
-        assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
-                .ulp(-Double.MIN_VALUE), 0D);
+		assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+				.ulp(Double.MIN_VALUE), 0D);
+		assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+				.ulp(-Double.MIN_VALUE), 0D);
 
-        assertEquals("Returned incorrect value", 2.220446049250313E-16,
-                StrictMath.ulp(1.0), 0D);
-        assertEquals("Returned incorrect value", 2.220446049250313E-16,
-                StrictMath.ulp(-1.0), 0D);
-        assertEquals("Returned incorrect value", 2.2737367544323206E-13,
-                StrictMath.ulp(1153.0), 0D);
+		assertEquals("Returned incorrect value", 2.220446049250313E-16,
+				StrictMath.ulp(1.0), 0D);
+		assertEquals("Returned incorrect value", 2.220446049250313E-16,
+				StrictMath.ulp(-1.0), 0D);
+		assertEquals("Returned incorrect value", 2.2737367544323206E-13,
+				StrictMath.ulp(1153.0), 0D);
     }
 
     /**
-     * @tests java.lang.StrictMath#ulp(float)
-     */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "ulp",
-        args = {float.class}
-    )
+	 * @tests java.lang.StrictMath#ulp(float)
+	 */
     @SuppressWarnings("boxing")
     public void test_ulp_f() {
         // Test for special cases
-        assertTrue("Should return NaN", Float.isNaN(StrictMath.ulp(Float.NaN)));
-        assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY,
-                StrictMath.ulp(Float.POSITIVE_INFINITY), 0f);
-        assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY,
-                StrictMath.ulp(Float.NEGATIVE_INFINITY), 0f);
-        assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath
-                .ulp(0.0f), 0f);
-        assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath
-                .ulp(+0.0f), 0f);
-        assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath
-                .ulp(-0.0f), 0f);
-        assertEquals("Returned incorrect value", 2.028241E31f, StrictMath
-                .ulp(Float.MAX_VALUE), 0f);
-        assertEquals("Returned incorrect value", 2.028241E31f, StrictMath
-                .ulp(-Float.MAX_VALUE), 0f);
+    	assertTrue("Should return NaN", Float.isNaN(StrictMath.ulp(Float.NaN)));
+		assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY,
+				StrictMath.ulp(Float.POSITIVE_INFINITY), 0f);
+		assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY,
+				StrictMath.ulp(Float.NEGATIVE_INFINITY), 0f);
+		assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath
+				.ulp(0.0f), 0f);
+		assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath
+				.ulp(+0.0f), 0f);
+		assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath
+				.ulp(-0.0f), 0f);
+		assertEquals("Returned incorrect value", 2.028241E31f, StrictMath
+				.ulp(Float.MAX_VALUE), 0f);
+		assertEquals("Returned incorrect value", 2.028241E31f, StrictMath
+				.ulp(-Float.MAX_VALUE), 0f);
 
-        assertEquals("Returned incorrect value", 1.4E-45f, StrictMath
-                .ulp(Float.MIN_VALUE), 0f);
-        assertEquals("Returned incorrect value", 1.4E-45f, StrictMath
-                .ulp(-Float.MIN_VALUE), 0f);
+		assertEquals("Returned incorrect value", 1.4E-45f, StrictMath
+				.ulp(Float.MIN_VALUE), 0f);
+		assertEquals("Returned incorrect value", 1.4E-45f, StrictMath
+				.ulp(-Float.MIN_VALUE), 0f);
 
-        assertEquals("Returned incorrect value", 1.1920929E-7f, StrictMath
-                .ulp(1.0f), 0f);
-        assertEquals("Returned incorrect value", 1.1920929E-7f, StrictMath
-                .ulp(-1.0f), 0f);
-        assertEquals("Returned incorrect value", 1.2207031E-4f, StrictMath
-                .ulp(1153.0f), 0f);
-        assertEquals("Returned incorrect value", 5.6E-45f, Math
-                .ulp(9.403954E-38f), 0f);
+		assertEquals("Returned incorrect value", 1.1920929E-7f, StrictMath
+				.ulp(1.0f), 0f);
+		assertEquals("Returned incorrect value", 1.1920929E-7f, StrictMath
+				.ulp(-1.0f), 0f);
+		assertEquals("Returned incorrect value", 1.2207031E-4f, StrictMath
+				.ulp(1153.0f), 0f);
+		assertEquals("Returned incorrect value", 5.6E-45f, Math
+				.ulp(9.403954E-38f), 0f);
     }
-    
-    @TestTargetNew(
-        level = TestLevel.PARTIAL,
-        notes = "Stress test.",
-        method = "pow",
-        args = {double.class, double.class}
-    )
-    public void test_pow_stress() {
-        assertTrue(Double.longBitsToDouble(-4610068591539890326L) ==
-                StrictMath.pow(-1.0000000000000002e+00,
-                        4.5035996273704970e+15));
-        assertTrue(Double.longBitsToDouble(4601023824101950163L) == 
-                StrictMath.pow(-9.9999999999999978e-01,
-                        4.035996273704970e+15));
-    }
-    
-    @TestTargetNew(
-        level = TestLevel.PARTIAL,
-        notes = "Stress test.",
-        method = "tan",
-        args = {double.class}
-    )
-    public void test_tan_stress(){
-        assertTrue(Double.longBitsToDouble(4850236541654588678L) == 
-            StrictMath.tan(1.7765241907548024E+269));
-    }
-    
 }
diff --git a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/StringTest.java b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/StringTest.java
index 4ad0c52..efbb198 100644
--- a/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/StringTest.java
+++ b/libcore/luni/src/test/java/org/apache/harmony/luni/tests/java/lang/StringTest.java
@@ -17,31 +17,40 @@
 
 package org.apache.harmony.luni.tests.java.lang;
 
-import dalvik.annotation.TestLevel;
-import dalvik.annotation.TestTargetClass;
-import dalvik.annotation.TestTargetNew;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Constructor;
+import java.nio.charset.Charset;
+import java.util.SortedMap;
 
 import junit.framework.TestCase;
 
-import java.io.UnsupportedEncodingException;
-import java.math.BigDecimal;
-
-@TestTargetClass(String.class) 
 public class StringTest extends TestCase {
 
-    private static String newString(int start, int len, char[] data) {
-        return new String(data, start,len);
+    private static final Constructor<String> UNSAFE_CONSTRUCTOR;
+    static {
+        Constructor<String> uc;
+        try {
+            uc = String.class.getDeclaredConstructor(new Class[] { int.class,
+                    int.class, char[].class });
+            uc.setAccessible(true);
+        } catch (Exception e) {
+            uc = null;
+        }
+        UNSAFE_CONSTRUCTOR = uc;
+    }
+
+    private static String newString(int start, int len, char[] data) throws Exception {
+        if (UNSAFE_CONSTRUCTOR == null) {
+            return new String(data, start, len);
+        }
+
+        return UNSAFE_CONSTRUCTOR.newInstance(Integer.valueOf(start), Integer.valueOf(len),
+                    data);
     }
     
     /**
      * @tests java.lang.String#String()
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "String",
-        args = {}
-    )
     public void test_Constructor() {
         assertEquals("Created incorrect string", "", new String());
     }
@@ -49,12 +58,6 @@
     /**
      * @tests java.lang.String#String(byte[])
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "String",
-        args = {byte[].class}
-    )
     public void test_Constructor$B() {
         assertEquals("Failed to create string", "HelloWorld", new String(
                 "HelloWorld".getBytes()));
@@ -63,12 +66,6 @@
     /**
      * @tests java.lang.String#String(byte[], int)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "String",
-        args = {byte[].class, int.class}
-    )
     @SuppressWarnings("deprecation")
     public void test_Constructor$BI() {
         String s = new String(new byte[] { 65, 66, 67, 68, 69 }, 0);
@@ -80,12 +77,6 @@
     /**
      * @tests java.lang.String#String(byte[], int, int)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "String",
-        args = {byte[].class, int.class, int.class}
-    )
     public void test_Constructor$BII() {
         byte[] hwba = "HelloWorld".getBytes();
         assertEquals("Failed to create string", "HelloWorld", new String(hwba,
@@ -101,12 +92,6 @@
     /**
      * @tests java.lang.String#String(byte[], int, int, int)
      */
-    @TestTargetNew(
-        level = TestLevel.PARTIAL,
-        notes = "IndexOutOfBoundsException is not verified.",
-        method = "String",
-        args = {byte[].class, int.class, int.class, int.class}
-    )
     @SuppressWarnings("deprecation")
     public void test_Constructor$BIII() {
         String s = new String(new byte[] { 65, 66, 67, 68, 69 }, 0, 1, 3);
@@ -118,33 +103,21 @@
     /**
      * @tests java.lang.String#String(byte[], int, int, java.lang.String)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "String",
-        args = {byte[].class, int.class, int.class, java.lang.String.class}
-    )
     public void test_Constructor$BIILjava_lang_String() throws Exception {
         String s = new String(new byte[] { 65, 66, 67, 68, 69 }, 0, 5, "8859_1");
         assertEquals("Incorrect string returned: " + s, "ABCDE", s);
         
         try {
-            new String(new byte[] { 65, 66, 67, 68, 69 }, 0, 5, "");
-            fail("Should throw UnsupportedEncodingException");
+        	new String(new byte[] { 65, 66, 67, 68, 69 }, 0, 5, "");
+        	fail("Should throw UnsupportedEncodingException");
         } catch (UnsupportedEncodingException e) {
-            //expected
+        	//expected
         }
     }
 
     /**
      * @tests java.lang.String#String(byte[], java.lang.String)
      */
-    @TestTargetNew(
-        level = TestLevel.PARTIAL,
-        notes = "UnsupportedEncodingException is not verified.",
-        method = "String",
-        args = {byte[].class, java.lang.String.class}
-    )
     public void test_Constructor$BLjava_lang_String() throws Exception {
         String s = new String(new byte[] { 65, 66, 67, 68, 69 }, "8859_1");
         assertEquals("Incorrect string returned: " + s, "ABCDE", s);
@@ -153,12 +126,6 @@
     /**
      * @tests java.lang.String#String(char[])
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "String",
-        args = {char[].class}
-    )
     public void test_Constructor$C() {
         assertEquals("Failed Constructor test", "World", new String(new char[] {
                 'W', 'o', 'r', 'l', 'd' }));
@@ -167,12 +134,6 @@
     /**
      * @tests java.lang.String#String(char[], int, int)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "String",
-        args = {char[].class, int.class, int.class}
-    )
     public void test_Constructor$CII() throws Exception {
         char[] buf = { 'H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd' };
         String s = new String(buf, 0, buf.length);
@@ -188,12 +149,6 @@
     /**
      * @tests java.lang.String#String(java.lang.String)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "String",
-        args = {java.lang.String.class}
-    )
     public void test_ConstructorLjava_lang_String() {
         String s = new String("Hello World");
         assertEquals("Failed to construct correct string", "Hello World", s);
@@ -202,12 +157,6 @@
     /**
      * @tests java.lang.String#String(java.lang.StringBuffer)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "String",
-        args = {java.lang.StringBuffer.class}
-    )
     public void test_ConstructorLjava_lang_StringBuffer() {
         StringBuffer sb = new StringBuffer();
         sb.append("HelloWorld");
@@ -217,12 +166,6 @@
     /**
      * @tests java.lang.String#String(java.lang.StringBuilder)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "String",
-        args = {java.lang.StringBuilder.class}
-    )
     public void test_ConstructorLjava_lang_StringBuilder() {
         StringBuilder sb = new StringBuilder(32);
         sb.append("HelloWorld");
@@ -238,12 +181,6 @@
     /**
      * @tests java.lang.String#String(int[],int,int)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "String",
-        args = {int[].class, int.class, int.class}
-    )
     public void test_Constructor$III() {
         assertEquals("HelloWorld", new String(new int[] { 'H', 'e', 'l', 'l',
                 'o', 'W', 'o', 'r', 'l', 'd' }, 0, 10));
@@ -292,13 +229,7 @@
     /**
      * @tests java.lang.String#contentEquals(CharSequence)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "contentEquals",
-        args = {java.lang.CharSequence.class}
-    )
-    public void test_contentEqualsLjava_lang_CharSequence() {
+    public void test_contentEqualsLjava_lang_CharSequence() throws Exception {
         String s = "abc";
         assertTrue(s.contentEquals((CharSequence) new StringBuffer("abc")));
         assertFalse(s.contentEquals((CharSequence) new StringBuffer("def")));
@@ -319,14 +250,8 @@
     /**
      * @tests java.lang.String#contentEquals(StringBuffer)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "contentEquals",
-        args = {java.lang.StringBuffer.class}
-    )
     @SuppressWarnings("nls")
-    public void test_boolean_contentEquals_StringBuffer() {
+    public void test_boolean_contentEquals_StringBuffer() throws Exception {
         String s = "abc";
         assertTrue(s.contentEquals(new StringBuffer("abc")));
         assertFalse(s.contentEquals(new StringBuffer("def")));
@@ -348,14 +273,8 @@
     /**
      * @tests java.lang.String#contains(CharSequence)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "contains",
-        args = {java.lang.CharSequence.class}
-    )
     @SuppressWarnings("cast")
-    public void test_containsLjava_lang_CharSequence() {
+    public void test_containsLjava_lang_CharSequence() throws Exception {
         String s = "abcdefghijklmnopqrstuvwxyz";
         assertTrue(s.contains((CharSequence) new StringBuffer("abc")));
         assertTrue(s.contains((CharSequence) new StringBuffer("def")));
@@ -376,13 +295,7 @@
     /**
      * @tests java.lang.String.offsetByCodePoints(int, int)'
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "offsetByCodePoints",
-        args = {int.class, int.class}
-    )
-    public void test_offsetByCodePointsII() {
+    public void test_offsetByCodePoints_II() throws Exception {
         int result = new String("a\uD800\uDC00b").offsetByCodePoints(0, 2);
         assertEquals(3, result);
 
@@ -505,13 +418,7 @@
     /**
      * @tests java.lang.StringBuilder.codePointAt(int)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "codePointAt",
-        args = {int.class}
-    )
-    public void test_codePointAtI() {
+    public void test_codePointAtI() throws Exception {
         String s = "abc";
         assertEquals('a', s.codePointAt(0));
         assertEquals('b', s.codePointAt(1));
@@ -572,13 +479,7 @@
     /**
      * @tests java.lang.StringBuilder.codePointBefore(int)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "codePointBefore",
-        args = {int.class}
-    )
-    public void test_codePointBeforeI() {
+    public void test_codePointBeforeI() throws Exception {
         String s = "abc";
         assertEquals('a', s.codePointBefore(1));
         assertEquals('b', s.codePointBefore(2));
@@ -639,13 +540,7 @@
     /**
      * @tests java.lang.StringBuilder.codePointCount(int, int)
      */
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
-        method = "codePointCount",
-        args = {int.class, int.class}
-    )
-    public void test_codePointCountII() {
+    public void test_codePointCountII() throws Exception {
         assertEquals(1, "\uD800\uDC00".codePointCount(0, 2));
         assertEquals(1, "\uD800\uDC01".codePointCount(0, 2));
         assertEquals(1, "\uD801\uDC01".codePointCount(0, 2));
@@ -700,40 +595,165 @@
         } catch (IndexOutOfBoundsException e) {
         }
     }
-
-    @TestTargetNew(
-        level = TestLevel.ADDITIONAL,
-        notes = "Regression test for some existing bugs and crashes",
-        method = "format",
-        args = { String.class, Object[].class }
-    )
-    public void testProblemCases() {
-        BigDecimal[] input = new BigDecimal[] {
-            new BigDecimal("20.00000"),
-            new BigDecimal("20.000000"),
-            new BigDecimal(".2"),
-            new BigDecimal("2"),
-            new BigDecimal("-2"),
-            new BigDecimal("200000000000000000000000"),
-            new BigDecimal("20000000000000000000000000000000000000000000000000")
-        };
-
-        String[] output = new String[] {
-                "20.00",
-                "20.00",
-                "0.20",
-                "2.00",
-                "-2.00",
-                "200000000000000000000000.00",
-                "20000000000000000000000000000000000000000000000000.00"
-        };
-        
-        for (int i = 0; i < input.length; i++) {
-            String result = String.format("%.2f", input[i]);
-            assertEquals("Format test for \"" + input[i] + "\" failed, " +
-                    "expected=" + output[i] + ", " +
-                    "actual=" + result, output[i], result);
+    
+    /**
+     * @tests {@link java.lang.String#String(byte[], int, int, Charset)} 
+     * 
+     * @since 1.6
+     */
+    public void test_ConstructorBIIL() throws Exception {
+        // can construct normally
+        new String(new byte[8], 0, 4, Charset.defaultCharset());
+        new String(new byte[8], 8, 0, Charset.defaultCharset());
+        new String(new byte[0], 0, 0, Charset.defaultCharset());
+        // throws exceptions
+        try {
+            new String(new byte[8], 0, 9, Charset.defaultCharset());
+            fail("should throw StringIndexOutOfBoundsException");
+        } catch (StringIndexOutOfBoundsException e) {
+            // expected
+        }
+        try {
+            new String(new byte[8], 9, 0, Charset.defaultCharset());
+            fail("should throw StringIndexOutOfBoundsException");
+        } catch (StringIndexOutOfBoundsException e) {
+            // expected
+        }
+        try {
+            new String(new byte[8], -1, 0, Charset.defaultCharset());
+            fail("should throw StringIndexOutOfBoundsException");
+        } catch (StringIndexOutOfBoundsException e) {
+            // expected
+        }
+        try {
+            new String(new byte[8], 9, -1, Charset.defaultCharset());
+            fail("should throw StringIndexOutOfBoundsException");
+        } catch (StringIndexOutOfBoundsException e) {
+            // expected
+        }
+        try {
+            new String(null, -1, 0, Charset.defaultCharset());
+            fail("should throw StringIndexOutOfBoundsException");
+        } catch (StringIndexOutOfBoundsException e) {
+            // expected
+        }
+        try {
+            new String(null, 0, -1, Charset.defaultCharset());
+            fail("should throw StringIndexOutOfBoundsException");
+        } catch (StringIndexOutOfBoundsException e) {
+            // expected
+        }
+        try {
+            new String(null, 0, 9, Charset.defaultCharset());
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        try {
+            new String(null, 0, 0, Charset.defaultCharset());
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        try {
+            new String(null, -1, 0, (Charset)null);
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        try {
+            new String(new byte[8], -1, 0, (Charset)null);
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        try {
+            new String(new byte[8], 0, 9, (Charset)null);
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        try {
+            new String(new byte[8], 0, 4, (Charset)null);
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
         }
     }
     
+    /**
+     * @tests {@link java.lang.String#String(byte[], Charset)}
+     * 
+     *  @since 1.6
+     */
+    public void test_ConstructorBL() throws Exception {
+        new String(new byte[8], Charset.defaultCharset());
+        try {
+            new String(new byte[8],(Charset)null);
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        try {
+            new String(new byte[0],(Charset)null);
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        try {
+            new String(null,Charset.defaultCharset());
+            fail("should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        new String(new byte[0], Charset.defaultCharset());
+    }
+    
+    /**
+     * @tests {@link java.lang.String#isEmpty()}
+     * 
+     * @since 1.6
+     */
+    public void test_isEmpty() throws Exception {
+        assertTrue(new String(new byte[0], Charset.defaultCharset()).isEmpty());
+        assertTrue(new String(new byte[8], Charset.defaultCharset()).substring(0, 0).isEmpty());
+    }
+    
+    /**
+     * @tests {@link java.lang.String#getBytes(Charset)}
+     * 
+     * @since 1.6
+     */
+    public void test_getBytesLCharset() throws Exception {
+        byte[] emptyBytes = new byte[0];
+        byte[] someBytes = new byte[]{'T','h','i','s',' ',' ','i','s',' ','t','e','s','t',' ','b','y','t','e','s'};
+        assertEquals(0, new String(emptyBytes, Charset.defaultCharset()).getBytes(Charset.defaultCharset()).length);
+        try{
+            new String(emptyBytes, Charset.defaultCharset()).getBytes((Charset)null);
+            fail("should throw NPE");
+        } catch (NullPointerException e){
+            // correct
+        }
+        assertTrue(bytesEquals(someBytes,new String(someBytes, Charset.defaultCharset()).getBytes(Charset.defaultCharset())));
+        SortedMap<String, Charset> charsets = Charset.availableCharsets();
+
+        Charset ascii = charsets.get("US-ASCII");
+        Charset utf8 = charsets.get("UTF-8");
+        if (charsets.size() >= 2){
+            // assertTrue(bytesEquals(someBytes,new String(someBytes, charsets.get(charsets.firstKey())).getBytes(charsets.get(charsets.lastKey()))));  android-changed: invalid test
+            assertFalse(bytesEquals("\u4f60\u597d".getBytes(ascii), "\u4f60\u597d".getBytes(utf8)));
+        }
+    }
+    
+    boolean bytesEquals(byte[] bytes1, byte[] bytes2){
+        if (bytes1.length == bytes2.length){
+            for (int i = 0; i < bytes1.length; i++){
+                if (bytes1[i] != bytes2[i]){
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/libcore/math/src/main/java/java/math/BigInt.java b/libcore/math/src/main/java/java/math/BigInt.java
index 6a1cb97..1f3ffdd 100644
--- a/libcore/math/src/main/java/java/math/BigInt.java
+++ b/libcore/math/src/main/java/java/math/BigInt.java
@@ -156,11 +156,7 @@
     }
 
     public void putDecString(String str) {
-        if (str == null) throw new NullPointerException();
-        if (str.length() == 0) {
-            // math.12=Zero length BigInteger
-            throw new NumberFormatException(Messages.getString("math.12")); //$NON-NLS-1$
-        }
+        checkString(str, 10);
         this.makeValid();
         int usedLen = NativeBN.BN_dec2bn(this.bignum, str);
         Check((usedLen > 0));
@@ -170,11 +166,7 @@
     }
 
     public void putHexString(String str) {
-        if (str == null) throw new NullPointerException();
-        if (str.length() == 0) {
-            // math.12=Zero length BigInteger
-            throw new NumberFormatException(Messages.getString("math.12")); //$NON-NLS-1$
-        }
+        checkString(str, 16);
         this.makeValid();
         int usedLen = NativeBN.BN_hex2bn(this.bignum, str);
         Check((usedLen > 0));
@@ -183,6 +175,31 @@
         }
     }
 
+    /**
+     * Throws if 's' doesn't match Java's rules for valid BigInteger strings.
+     * BN_dec2bn and BN_hex2bn do very little checking, so we need to manually
+     * ensure we comply with Java's rules.
+     * http://code.google.com/p/android/issues/detail?id=7036
+     */
+    public void checkString(String s, int radix) {
+        if (s == null) {
+            throw new NullPointerException();
+        }
+        // A valid big integer consists of an optional '-' followed by
+        // one or more digit characters appropriate to the given radix,
+        // and no other characters.
+        final int charCount = s.length();
+        int i = (charCount > 0 && s.charAt(0) == '-') ? 1 : 0;
+        if (charCount - i == 0) {
+            throw new NumberFormatException(s);
+        }
+        for (; i < charCount; ++i) {
+            if (Character.digit(s.charAt(i), radix) == -1) {
+                throw new NumberFormatException(s);
+            }
+        }
+    }
+
     public void putBigEndian(byte[] a, boolean neg) {
         this.makeValid();
         Check(NativeBN.BN_bin2bn(a, a.length, neg, this.bignum));
diff --git a/libcore/nio/src/main/java/java/nio/DoubleBuffer.java b/libcore/nio/src/main/java/java/nio/DoubleBuffer.java
index 4e0ab01..3bea69e 100644
--- a/libcore/nio/src/main/java/java/nio/DoubleBuffer.java
+++ b/libcore/nio/src/main/java/java/nio/DoubleBuffer.java
@@ -233,12 +233,17 @@
     public abstract DoubleBuffer duplicate();
 
     /**
-     * Checks whether this double buffer is equal to another object.
-     * <p>
-     * If {@code other} is not a double buffer then {@code false} is returned.
-     * Two double buffers are equal if and only if their remaining doubles are
-     * exactly the same. Position, limit, capacity and mark are not considered.
-     *
+     * Checks whether this double buffer is equal to another object. If {@code
+     * other} is not a {@code DoubleBuffer} then {@code false} is returned.
+     * 
+     * <p>Two double buffers are equal if their remaining doubles are equal.
+     * Position, limit, capacity and mark are not considered.
+     * 
+     * <p>This method considers two doubles {@code a} and {@code b} to be equal
+     * if {@code a == b} or if {@code a} and {@code b} are both {@code NaN}.
+     * Unlike {@link Double#equals}, this method considers {@code -0.0} and
+     * {@code +0.0} to be equal.
+     * 
      * @param other
      *            the object to compare with this double buffer.
      * @return {@code true} if this double buffer is equal to {@code other},
@@ -259,7 +264,9 @@
         int otherPosition = otherBuffer.position;
         boolean equalSoFar = true;
         while (equalSoFar && (myPosition < limit)) {
-            equalSoFar = get(myPosition++) == otherBuffer.get(otherPosition++);
+            double a = get(myPosition++);
+            double b = otherBuffer.get(otherPosition++);
+            equalSoFar = a == b || (a != a && b != b);
         }
 
         return equalSoFar;
diff --git a/libcore/nio/src/main/java/java/nio/FloatBuffer.java b/libcore/nio/src/main/java/java/nio/FloatBuffer.java
index cab94c3..15239b1 100644
--- a/libcore/nio/src/main/java/java/nio/FloatBuffer.java
+++ b/libcore/nio/src/main/java/java/nio/FloatBuffer.java
@@ -233,12 +233,17 @@
     public abstract FloatBuffer duplicate();
 
     /**
-     * Checks whether this float buffer is equal to another object.
-     * <p>
-     * If {@code other} is not a float buffer then {@code false} is returned.
-     * Two float buffers are equal if and only if their remaining floats are
-     * exactly the same. Position, limit, capacity and mark are not considered.
-     *
+     * Checks whether this float buffer is equal to another object. If {@code
+     * other} is not a {@code FloatBuffer} then {@code false} is returned.
+     * 
+     * <p>Two float buffers are equal if their remaining floats are equal.
+     * Position, limit, capacity and mark are not considered.
+     * 
+     * <p>This method considers two floats {@code a} and {@code b} to be equal
+     * if {@code a == b} or if {@code a} and {@code b} are both {@code NaN}.
+     * Unlike {@link Float#equals}, this method considers {@code -0.0} and
+     * {@code +0.0} to be equal.
+     * 
      * @param other
      *            the object to compare with this float buffer.
      * @return {@code true} if this float buffer is equal to {@code other},
@@ -259,7 +264,9 @@
         int otherPosition = otherBuffer.position;
         boolean equalSoFar = true;
         while (equalSoFar && (myPosition < limit)) {
-            equalSoFar = get(myPosition++) == otherBuffer.get(otherPosition++);
+            float a = get(myPosition++);
+            float b = otherBuffer.get(otherPosition++);
+            equalSoFar = a == b || (a != a && b != b);
         }
 
         return equalSoFar;
diff --git a/libcore/nio/src/main/java/org/apache/harmony/nio/internal/MappedByteBufferFactory.java b/libcore/nio/src/main/java/org/apache/harmony/nio/internal/MappedByteBufferFactory.java
index b598c15..94d6219 100644
--- a/libcore/nio/src/main/java/org/apache/harmony/nio/internal/MappedByteBufferFactory.java
+++ b/libcore/nio/src/main/java/org/apache/harmony/nio/internal/MappedByteBufferFactory.java
@@ -56,7 +56,7 @@
          * than Integer.MAX_VALUE, so long to int cast is safe here.
          */
         return (MappedByteBuffer) constructor.newInstance(new Object[] { addr,
-                new Integer((int) size), new Integer(offset),
-                new Integer(mapmode) });
+                Integer.valueOf((int) size), Integer.valueOf(offset),
+                Integer.valueOf(mapmode) });
     }
 }
diff --git a/libcore/security/src/main/files/certimport.sh b/libcore/security/src/main/files/certimport.sh
index c021a10..ca36a70 100755
--- a/libcore/security/src/main/files/certimport.sh
+++ b/libcore/security/src/main/files/certimport.sh
@@ -7,12 +7,40 @@
 
 CERTSTORE=cacerts.bks
 
+# put required 1.6 VM at head of PATH
+JDK6PATH=/usr/lib/jvm/java-6-sun/bin
+if [ ! -e $JDK6PATH/java ] ; then
+  set +x
+  echo
+  echo "WARNING: could not find $JDK6PATH/java but continuing anyway."
+  echo "    you might consider making sure the expected JDK is installed"
+  echo "    or updating its location in this script."
+  echo
+  set -x
+fi
+export PATH=$JDK6PATH:$PATH
+
 # Check java version.
 JAVA_VERSION=`java -version 2>&1 | head -1`
 JAVA_VERSION_MINOR=`expr match "$JAVA_VERSION" "java version \"[1-9]\.\([0-9]\).*\""`
 if [ $JAVA_VERSION_MINOR -lt 6 ]; then
-  echo "java version 1.6 or greater required for keytool usage"
-  exit 255
+  set +x
+  echo
+  echo "ERROR: java version 1.6 or greater required for keytool usage"
+  echo
+  exit 1
+fi
+
+PROVIDER_CLASS=org.bouncycastle.jce.provider.BouncyCastleProvider
+PROVIDER_PATH=/usr/share/java/bcprov.jar
+
+if [ ! -e $PROVIDER_PATH ] ; then
+  set +x
+  echo
+  echo "ERROR: could not find provider path $PROVIDER_PATH. Try installing with:"
+  echo "    sudo apt-get install libbcprov-java"
+  echo
+  exit 1
 fi
 
 if [ -a $CERTSTORE ]; then
@@ -34,8 +62,8 @@
       -file <(openssl x509 -in cacerts/$cert) \
       -keystore $CERTSTORE \
       -storetype BKS \
-      -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
-      -providerpath /usr/share/java/bcprov.jar \
+      -provider $PROVIDER_CLASS \
+      -providerpath $PROVIDER_PATH \
       -storepass $STOREPASS
   let "COUNTER=$COUNTER + 1"
 done
diff --git a/libcore/security/src/main/java/java/security/cert/X509CertSelector.java b/libcore/security/src/main/java/java/security/cert/X509CertSelector.java
index e2de95b..0460fd6 100644
--- a/libcore/security/src/main/java/java/security/cert/X509CertSelector.java
+++ b/libcore/security/src/main/java/java/security/cert/X509CertSelector.java
@@ -751,7 +751,6 @@
         ArrayList result = new ArrayList();
         for (int tag=0; tag<9; tag++) {
             if (subjectAltNames[tag] != null) {
-                Integer teg = new Integer(tag);
                 for (int name=0; name<subjectAltNames[tag].size(); name++) {
                     Object neim = subjectAltNames[tag].get(name);
                     if (neim instanceof byte[]) {
@@ -760,7 +759,7 @@
                         System.arraycopy(arr_neim, 0, neim, 0, arr_neim.length);
                     }
                     List list = new ArrayList(2);
-                    list.add(teg);
+                    list.add(Integer.valueOf(tag)); // android-changed
                     list.add(neim);
                     result.add(list);
                 }
@@ -1431,4 +1430,3 @@
         return result;
     }
 }
-
diff --git a/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralName.java b/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralName.java
index 3b291a1..dcf4b94 100644
--- a/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralName.java
+++ b/libcore/security/src/main/java/org/apache/harmony/security/x509/GeneralName.java
@@ -463,7 +463,7 @@
      */
     public List getAsList() {
         ArrayList result = new ArrayList();
-        result.add(new Integer(tag));
+        result.add(Integer.valueOf(tag)); // android-changed
         switch (tag) {
             case OTHER_NAME:
                 result.add(((OtherName) name).getEncoded());
diff --git a/libcore/security/src/main/java/org/bouncycastle/crypto/macs/HMac.java b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/HMac.java
index 0bd4d39..7272f32 100644
--- a/libcore/security/src/main/java/org/bouncycastle/crypto/macs/HMac.java
+++ b/libcore/security/src/main/java/org/bouncycastle/crypto/macs/HMac.java
@@ -32,23 +32,23 @@
     {
         blockLengths = new Hashtable();
         
-        blockLengths.put("GOST3411", new Integer(32));
+        blockLengths.put("GOST3411", Integer.valueOf(32));
         
-        blockLengths.put("MD2", new Integer(16));
-        blockLengths.put("MD4", new Integer(64));
-        blockLengths.put("MD5", new Integer(64));
+        blockLengths.put("MD2", Integer.valueOf(16));
+        blockLengths.put("MD4", Integer.valueOf(64));
+        blockLengths.put("MD5", Integer.valueOf(64));
         
-        blockLengths.put("RIPEMD128", new Integer(64));
-        blockLengths.put("RIPEMD160", new Integer(64));
+        blockLengths.put("RIPEMD128", Integer.valueOf(64));
+        blockLengths.put("RIPEMD160", Integer.valueOf(64));
         
-        blockLengths.put("SHA-1", new Integer(64));
-        blockLengths.put("SHA-224", new Integer(64));
-        blockLengths.put("SHA-256", new Integer(64));
-        blockLengths.put("SHA-384", new Integer(128));
-        blockLengths.put("SHA-512", new Integer(128));
+        blockLengths.put("SHA-1", Integer.valueOf(64));
+        blockLengths.put("SHA-224", Integer.valueOf(64));
+        blockLengths.put("SHA-256", Integer.valueOf(64));
+        blockLengths.put("SHA-384", Integer.valueOf(128));
+        blockLengths.put("SHA-512", Integer.valueOf(128));
         
-        blockLengths.put("Tiger", new Integer(64));
-        blockLengths.put("Whirlpool", new Integer(64));
+        blockLengths.put("Tiger", Integer.valueOf(64));
+        blockLengths.put("Whirlpool", Integer.valueOf(64));
     }
     
     private static int getByteLength(
diff --git a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java
index cb3b172..24233d6 100644
--- a/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java
+++ b/libcore/security/src/main/java/org/bouncycastle/jce/provider/JDKKeyPairGenerator.java
@@ -397,9 +397,9 @@
 //        static {
 //            ecParameters = new Hashtable();
 //
-//            ecParameters.put(new Integer(192), new ECGenParameterSpec("prime192v1"));
-//            ecParameters.put(new Integer(239), new ECGenParameterSpec("prime239v1"));
-//            ecParameters.put(new Integer(256), new ECGenParameterSpec("prime256v1"));
+//            ecParameters.put(Integer.valueOf(192), new ECGenParameterSpec("prime192v1"));
+//            ecParameters.put(Integer.valueOf(239), new ECGenParameterSpec("prime239v1"));
+//            ecParameters.put(Integer.valueOf(256), new ECGenParameterSpec("prime256v1"));
 //        }
 //
 //        public EC()
@@ -421,7 +421,7 @@
 //        {
 //            this.strength = strength;
 //            this.random = random;
-//            this.ecParams = (ECGenParameterSpec)ecParameters.get(new Integer(strength));
+//            this.ecParams = (ECGenParameterSpec)ecParameters.get(Integer.valueOf(strength));
 //
 //            if (ecParams != null)
 //            {
diff --git a/libcore/security/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java b/libcore/security/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java
index 50037db..cc00697 100644
--- a/libcore/security/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java
+++ b/libcore/security/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java
@@ -662,7 +662,7 @@
         }
 
         ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.totalPathLength",
-                new Object[] {new Integer(totalPathLength)});
+                new Object[] {Integer.valueOf(totalPathLength)});
         
         addNotification(msg);
     }
@@ -697,7 +697,7 @@
                 // conflicting trust anchors                
                 ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
                         "CertPathReviewer.conflictingTrustAnchors",
-                        new Object[] {new Integer(trustColl.size()),
+                        new Object[] {Integer.valueOf(trustColl.size()),
                                       new UntrustedInput(cert.getIssuerX500Principal())});
                 addError(msg);
             }
@@ -706,7 +706,7 @@
                 ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
                         "CertPathReviewer.noTrustAnchorFound",
                         new Object[] {new UntrustedInput(cert.getIssuerX500Principal()),
-                                      new Integer(pkixParams.getTrustAnchors().size())});
+                                Integer.valueOf(pkixParams.getTrustAnchors().size())});
                 addError(msg);
             }
             else
@@ -1883,7 +1883,7 @@
                     else
                     {
                         msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcLimitValueNum",
-                                new Object[] {new Integer(limit.getCurrency().getNumeric()),
+                                new Object[] {Integer.valueOf(limit.getCurrency().getNumeric()),
                                               new Double(value),
                                               limit});
                     }
@@ -1978,7 +1978,7 @@
                         "CertPathReviewer.noCrlInCertstore",
                         new Object[] {new UntrustedInput(crlselect.getIssuers()),
                                       new UntrustedInput(nonMatchingCrlNames),
-                                      new Integer(numbOfCrls)});
+                                      Integer.valueOf(numbOfCrls)});
                 addNotification(msg,index);
             }
 
diff --git a/libcore/sql/src/main/java/java/sql/package.html b/libcore/sql/src/main/java/java/sql/package.html
index 9ae2488..0799bb7 100644
--- a/libcore/sql/src/main/java/java/sql/package.html
+++ b/libcore/sql/src/main/java/java/sql/package.html
@@ -1,8 +1,10 @@
 <html>
-  <body>
-    <p>
-      Provides a standard interface for accessing SQL-based databases.
-    </p>
-    @since Android 1.0
-  </body>
-</html>
\ No newline at end of file
+<body>
+<p>Provides a compatibility interface for accessing SQL-based databases.
+The <code>android.database</code> and <code>android.database.sqlite</code>
+packages offer a higher-performance alternative where source compatibility
+is not an issue.</p>
+
+<p>Note that you must provide your own JDBC driver.</p>
+</body>
+</html>
diff --git a/libcore/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCDatabaseMetaData.java b/libcore/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCDatabaseMetaData.java
index 2357c38..8d76173 100644
--- a/libcore/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCDatabaseMetaData.java
+++ b/libcore/sqlite-jdbc/src/main/java/SQLite/JDBC2y/JDBCDatabaseMetaData.java
@@ -637,7 +637,7 @@
 	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
 	    Hashtable<String, Integer> h = new Hashtable<String, Integer>();
 	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
-		h.put(rs0.tr.column[i], new Integer(i));
+		h.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
 	    }
 	    if (columnNamePattern != null &&
 		columnNamePattern.charAt(0) == '%') {
@@ -672,8 +672,7 @@
 		row[14] = "0";
 		row[15] = "65536";
 		col = ((Integer) h.get("cid")).intValue();
-		Integer cid = new Integer(r0[col]);
-		row[16] = "" + (cid.intValue() + 1);
+		row[16] = Integer.toString(Integer.parseInt(r0[col]) + 1); // android-changed
 		col = ((Integer) h.get("notnull")).intValue();
 		row[17] = (r0[col].charAt(0) == '0') ? "YES" : "NO";
 		row[10] = (r0[col].charAt(0) == '0') ? "" + columnNullable :
@@ -769,11 +768,11 @@
 	    rs1 != null && rs1.tr != null && rs1.tr.nrows > 0) {
 	    Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
 	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
-		h0.put(rs0.tr.column[i], new Integer(i));
+		h0.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
 	    }
 	    Hashtable<String, Integer> h1 = new Hashtable<String, Integer>();
 	    for (int i = 0; i < rs1.tr.ncolumns; i++) {
-		h1.put(rs1.tr.column[i], new Integer(i));
+		h1.put(rs1.tr.column[i], Integer.valueOf(i)); // android-changed
 	    }
 	    for (int i = 0; i < rs0.tr.nrows; i++) {
 		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
@@ -800,7 +799,7 @@
 		Hashtable<String, Integer> h2 =
 		    new Hashtable<String, Integer>();
 		for (int k = 0; k < rs2.tr.ncolumns; k++) {
-		    h2.put(rs2.tr.column[k], new Integer(k));
+		    h2.put(rs2.tr.column[k], Integer.valueOf(k)); // android-changed
 		}
 		for (int k = 0; k < rs2.tr.nrows; k++) {
 		    String r2[] = (String [])(rs2.tr.rows.elementAt(k));
@@ -892,7 +891,7 @@
 	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
 	    Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
 	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
-		h0.put(rs0.tr.column[i], new Integer(i));
+		h0.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
 	    }
 	    for (int i = 0; i < rs0.tr.nrows; i++) {
 		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
@@ -919,7 +918,7 @@
 		Hashtable<String, Integer> h1 =
 		    new Hashtable<String, Integer>();
 		for (int k = 0; k < rs1.tr.ncolumns; k++) {
-		    h1.put(rs1.tr.column[k], new Integer(k));
+		    h1.put(rs1.tr.column[k], Integer.valueOf(k)); // android-changed
 		}
 		for (int k = 0; k < rs1.tr.nrows; k++) {
 		    String r1[] = (String [])(rs1.tr.rows.elementAt(k));
@@ -952,7 +951,7 @@
 	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
 	    Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
 	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
-		h0.put(rs0.tr.column[i], new Integer(i));
+		h0.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
 	    }
 	    for (int i = 0; i < rs0.tr.nrows; i++) {
 		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
@@ -985,7 +984,7 @@
 				      JDBCResultSet in, TableResultX out) {
 	Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
 	for (int i = 0; i < in.tr.ncolumns; i++) {
-	    h0.put(in.tr.column[i], new Integer(i));
+	    h0.put(in.tr.column[i], Integer.valueOf(i)); // android-changed
 	}
 	for (int i = 0; i < in.tr.nrows; i++) {
 	    String r0[] = (String [])(in.tr.rows.elementAt(i));
@@ -1312,7 +1311,7 @@
 	if (rs0 != null && rs0.tr != null && rs0.tr.nrows > 0) {
 	    Hashtable<String, Integer> h0 = new Hashtable<String, Integer>();
 	    for (int i = 0; i < rs0.tr.ncolumns; i++) {
-		h0.put(rs0.tr.column[i], new Integer(i));
+		h0.put(rs0.tr.column[i], Integer.valueOf(i)); // android-changed
 	    }
 	    for (int i = 0; i < rs0.tr.nrows; i++) {
 		String r0[] = (String [])(rs0.tr.rows.elementAt(i));
@@ -1339,7 +1338,7 @@
 		Hashtable<String, Integer> h1 =
 		    new Hashtable<String, Integer>();
 		for (int k = 0; k < rs1.tr.ncolumns; k++) {
-		    h1.put(rs1.tr.column[k], new Integer(k));
+		    h1.put(rs1.tr.column[k], Integer.valueOf(k)); // android-changed
 		}
 		for (int k = 0; k < rs1.tr.nrows; k++) {
 		    String r1[] = (String [])(rs1.tr.rows.elementAt(k));
diff --git a/libcore/sqlite-jdbc/src/main/java/SQLite/Stmt.java b/libcore/sqlite-jdbc/src/main/java/SQLite/Stmt.java
index d60e6b0..f959ed2 100644
--- a/libcore/sqlite-jdbc/src/main/java/SQLite/Stmt.java
+++ b/libcore/sqlite-jdbc/src/main/java/SQLite/Stmt.java
@@ -227,7 +227,7 @@
     public Object column(int col) throws SQLite.Exception {
         switch (column_type(col)) {
 	case Constants.SQLITE_INTEGER:
-	    return new Long(column_long(col));
+            return Long.valueOf(column_long(col)); // android-changed: performance
 	case Constants.SQLITE_FLOAT:
 	    return new Double(column_double(col));
 	case Constants.SQLITE_BLOB:
diff --git a/libcore/text/src/main/java/java/text/DateFormat.java b/libcore/text/src/main/java/java/text/DateFormat.java
index bf7ebbe..2a329e1 100644
--- a/libcore/text/src/main/java/java/text/DateFormat.java
+++ b/libcore/text/src/main/java/java/text/DateFormat.java
@@ -874,9 +874,8 @@
         protected Field(String fieldName, int calendarField) {
             super(fieldName);
             this.calendarField = calendarField;
-            if (calendarField != -1
-                    && table.get(new Integer(calendarField)) == null) {
-                table.put(new Integer(calendarField), this);
+            if (calendarField != -1 && table.get(Integer.valueOf(calendarField)) == null) {
+                table.put(Integer.valueOf(calendarField), this);
             }
         }
 
@@ -906,7 +905,7 @@
                 throw new IllegalArgumentException();
             }
 
-            return table.get(new Integer(calendarField));
+            return table.get(Integer.valueOf(calendarField));
         }
 
         /**
diff --git a/libcore/text/src/main/java/java/text/MessageFormat.java b/libcore/text/src/main/java/java/text/MessageFormat.java
index f6074b2..4dc684d 100644
--- a/libcore/text/src/main/java/java/text/MessageFormat.java
+++ b/libcore/text/src/main/java/java/text/MessageFormat.java
@@ -226,7 +226,7 @@
  *
  * <pre>
  * Object[] arguments = {
- *         new Integer(7), new Date(System.currentTimeMillis()),
+ *         Integer.valueOf(7), new Date(System.currentTimeMillis()),
  *         "a disturbance in the Force"};
  * String result = MessageFormat.format(
  *         "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
@@ -245,7 +245,7 @@
  * Example 2: <blockquote>
  *
  * <pre>
- * Object[] testArgs = {new Long(3), "MyDisk"};
+ * Object[] testArgs = {Long.valueOf(3), "MyDisk"};
  * MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0} file(s).");
  * System.out.println(form.format(testArgs));
  * <em>
@@ -269,7 +269,7 @@
  * String[] filepart = {"no files","one file","{0,number} files"};
  * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
  * form.setFormatByArgumentIndex(0, fileform);
- * Object[] testArgs = {new Long(12373), "MyDisk"};
+ * Object[] testArgs = {Long.valueOf(12373), "MyDisk"};
  * System.out.println(form.format(testArgs));
  * <em>
  * Output (with different testArgs):
@@ -621,21 +621,14 @@
 
     /**
      * Adds a new FieldContainer with MessageFormat.Field.ARGUMENT field,
-     * argnumber, begin and end index to the fields vector, or sets the
+     * argIndex, begin and end index to the fields vector, or sets the
      * position's begin and end index if it has MessageFormat.Field.ARGUMENT as
      * its field attribute.
-     * 
-     * @param begin
-     * @param end
-     * @param argnumber
-     * @param position
-     * @param fields
      */
-    private void handleArgumentField(int begin, int end, int argnumber,
+    private void handleArgumentField(int begin, int end, int argIndex,
             FieldPosition position, Vector<FieldContainer> fields) {
         if (fields != null) {
-            fields.add(new FieldContainer(begin, end, Field.ARGUMENT,
-                    new Integer(argnumber)));
+            fields.add(new FieldContainer(begin, end, Field.ARGUMENT, Integer.valueOf(argIndex)));
         } else {
             if (position != null
                     && position.getFieldAttribute() == Field.ARGUMENT
diff --git a/libcore/tools/runner/expectations.txt b/libcore/tools/runner/expectations.txt
index 0ea91d0..b19cafe 100644
--- a/libcore/tools/runner/expectations.txt
+++ b/libcore/tools/runner/expectations.txt
@@ -18,16 +18,6 @@
 pattern .*Test failed: should get token \[, but get -1.*
 
 
-# These tests rely on Java 6 APIs
-test java.util.Arrays.Big
-result COMPILE_FAILED
-pattern .*cannot find symbol.*
-
-test java.util.Arrays.CopyMethods
-result COMPILE_FAILED
-pattern .*cannot find symbol.*
-
-
 # Dalvik doesn't include the "SunJCE" crypto provider
 test com.sun.crypto.provider.Cipher.AES.Test4513830
 result EXEC_FAILED
@@ -684,48 +674,6 @@
 pattern .*got java\.lang\.StringIndexOutOfBoundsException: null - FAILED.*
 
 
-# We don't expose Java 6 APIs
-test java.lang.String.Exceptions
-result COMPILE_FAILED
-pattern .*cannot find symbol.*new String.*
-
-test java.lang.String.Encodings
-result COMPILE_FAILED
-pattern .*cannot find symbol.*new String.*
-
-test java.io.File.GetXSpace
-result COMPILE_FAILED
-pattern .*cannot find symbol.*method getTotalSpace\(\).*
-
-test java.io.File.MaxPathLength
-result COMPILE_FAILED
-pattern .*cannot find symbol.*method getTotalSpace\(\).*
-
-test java.io.File.SetAccess (from File)
-result COMPILE_FAILED
-pattern .*method setWritable\(boolean,boolean\).*
-
-test java.io.PipedInputStream.Constructors
-result COMPILE_FAILED
-pattern .*constructor PipedInputStream\(int\).*
-
-test java.io.PipedReader.Constructors
-result COMPILE_FAILED
-pattern .*constructor PipedReader\(int\).*
-
-test java.io.File.SetAccess
-result COMPILE_FAILED
-pattern .*cannot find symbol.*method setWritable\(boolean,boolean\).*
-
-test java.io.PipedWriter.WriteAfterReaderClose
-result COMPILE_FAILED
-pattern .*cannot find symbol.*method clearError().*
-
-test java.io.PrintWriter.ClearErrorWriter
-result COMPILE_FAILED
-pattern .*cannot find symbol.*method clearError().*
-
-
 # A low-impact bug that we're ignoring: "Shared FileDescriptors get closed too early"
 #   http://code.google.com/p/android/issues/detail?id=5923
 test java.io.FileDescriptor.Finalize
diff --git a/libcore/tools/runner/java/dalvik/runner/TestRunner.java b/libcore/tools/runner/java/dalvik/runner/TestRunner.java
index a706d40..dce6b2d 100644
--- a/libcore/tools/runner/java/dalvik/runner/TestRunner.java
+++ b/libcore/tools/runner/java/dalvik/runner/TestRunner.java
@@ -85,6 +85,9 @@
     }
 
     public static void main(String[] args) {
+        if (args.length != 0) {
+            throw new RuntimeException("TestRunner doesn't take arguments");
+        }
         System.out.println(TestProperties.result(new TestRunner().run()));
     }
 }
diff --git a/libcore/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java b/libcore/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java
index 4e689fb..56a4817 100644
--- a/libcore/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java
+++ b/libcore/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java
@@ -32,12 +32,14 @@
  * the DOM implementation can easily access them while maintaining the DOM tree
  * structure.
  */
-public class AttrImpl extends NodeImpl implements Attr {
+public final class AttrImpl extends NodeImpl implements Attr {
 
     // Maintained by ElementImpl.
     ElementImpl ownerElement;
 
     private boolean namespaceAware;
+
+    boolean isId;
     
     private String namespaceURI;
 
@@ -159,10 +161,11 @@
     }
 
     public TypeInfo getSchemaTypeInfo() {
-        throw new UnsupportedOperationException(); // TODO
+        // TODO: populate this when we support XML Schema
+        return NULL_TYPE_INFO;
     }
 
     public boolean isId() {
-        throw new UnsupportedOperationException(); // TODO
+        return isId;
     }
 }
diff --git a/libcore/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java b/libcore/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
index b1802a6..c677e58 100644
--- a/libcore/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
+++ b/libcore/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
@@ -17,17 +17,14 @@
 package org.apache.harmony.xml.dom;
 
 import org.w3c.dom.Attr;
-import org.w3c.dom.CDATASection;
 import org.w3c.dom.CharacterData;
 import org.w3c.dom.Comment;
 import org.w3c.dom.DOMConfiguration;
 import org.w3c.dom.DOMException;
 import org.w3c.dom.DOMImplementation;
 import org.w3c.dom.Document;
-import org.w3c.dom.DocumentFragment;
 import org.w3c.dom.DocumentType;
 import org.w3c.dom.Element;
-import org.w3c.dom.EntityReference;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -76,7 +73,7 @@
      * attach user data to the document to save those fields. Xerces also takes
      * this approach.
      */
-    private WeakHashMap<Node, Map<String, UserData>> nodeToUserData;
+    private WeakHashMap<NodeImpl, Map<String, UserData>> nodeToUserData;
 
     public DocumentImpl(DOMImplementationImpl impl, String namespaceURI,
             String qualifiedName, DocumentType doctype, String inputEncoding) {
@@ -120,147 +117,232 @@
         
         return true;
     }
-    
-    /**
-     * Clones a node and (if requested) its children. The source node(s) may
-     * have been created by a different DocumentImpl or even DOM implementation.
-     * 
-     * @param node The node to clone.
-     * @param deep If true, a deep copy is created (including all child nodes).
-     * 
-     * @return The new node.
-     */
-    Node cloneNode(Node node, boolean deep) throws DOMException {
-        Node target;
-        
-        switch (node.getNodeType()) {
-            case Node.ATTRIBUTE_NODE: {
-                Attr source = (Attr)node;
-                target = createAttributeNS(source.getNamespaceURI(), source.getLocalName());
-                target.setPrefix(source.getPrefix());
-                target.setNodeValue(source.getNodeValue());
-                break;
-            }
-            case Node.CDATA_SECTION_NODE: {
-                CharacterData source = (CharacterData)node;
-                target = createCDATASection(source.getData());
-                break;
-            }
-            case Node.COMMENT_NODE: {
-                Comment source = (Comment)node;
-                target = createComment(source.getData());
-                break;
-            }
-            case Node.DOCUMENT_FRAGMENT_NODE: {
-                // Source is irrelevant in this case.
-                target = createDocumentFragment();
-                break;
-            }
-            case Node.DOCUMENT_NODE: {
-                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone a Document node");
-            }
-            case Node.DOCUMENT_TYPE_NODE: {
-                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone a DocumentType node");
-            }
-            case Node.ELEMENT_NODE: {
-                Element source = (Element)node;
-                target = createElementNS(source.getNamespaceURI(), source.getLocalName());
-                target.setPrefix(source.getPrefix());
 
-                NamedNodeMap map = source.getAttributes();
-                for (int i = 0; i < map.getLength(); i++) {
-                    Attr attr = (Attr)map.item(i);
-                    ((Element)target).setAttributeNodeNS((Attr)cloneNode(attr, deep));
+    /**
+     * Returns a shallow copy of the given node. If the node is an element node,
+     * its attributes are always copied.
+     *
+     * @param node a node belonging to any document or DOM implementation.
+     * @param operation the operation type to use when notifying user data
+     *     handlers of copied element attributes. It is the caller's
+     *     responsibility to notify user data handlers of the returned node.
+     * @return a new node whose document is this document and whose DOM
+     *     implementation is this DOM implementation.
+     */
+    private NodeImpl shallowCopy(short operation, Node node) {
+        switch (node.getNodeType()) {
+            case Node.ATTRIBUTE_NODE:
+                Attr attr = (Attr) node;
+                AttrImpl attrCopy = createAttributeNS(attr.getNamespaceURI(), attr.getLocalName());
+                attrCopy.setPrefix(attr.getPrefix());
+                attrCopy.setNodeValue(attr.getNodeValue());
+                return attrCopy;
+
+            case Node.CDATA_SECTION_NODE:
+                return createCDATASection(((CharacterData) node).getData());
+
+            case Node.COMMENT_NODE:
+                return createComment(((Comment) node).getData());
+
+            case Node.DOCUMENT_FRAGMENT_NODE:
+                return createDocumentFragment();
+
+            case Node.DOCUMENT_NODE:
+            case Node.DOCUMENT_TYPE_NODE:
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+                        "Cannot copy node of type " + node.getNodeType());
+
+            case Node.ELEMENT_NODE:
+                Element element = (Element) node;
+                ElementImpl elementCopy = createElementNS(
+                        element.getNamespaceURI(), element.getLocalName());
+                elementCopy.setPrefix(element.getPrefix());
+                NamedNodeMap attributes = element.getAttributes();
+                for (int i = 0; i < attributes.getLength(); i++) {
+                    Node elementAttr = attributes.item(i);
+                    AttrImpl elementAttrCopy = (AttrImpl) shallowCopy(operation, elementAttr);
+                    notifyUserDataHandlers(operation, elementAttr, elementAttrCopy);
+                    elementCopy.setAttributeNodeNS(elementAttrCopy);
                 }
-                break;
-            }
-            case Node.ENTITY_NODE: {
-                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone an Entity node");
-            }
-            case Node.ENTITY_REFERENCE_NODE: {
-                EntityReference source = (EntityReference)node;
-                target = createEntityReference(source.getNodeName());
-                break;
-            }
-            case Node.NOTATION_NODE: {
-                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone a Notation node");
-            }
-            case Node.PROCESSING_INSTRUCTION_NODE: {
-                ProcessingInstruction source = (ProcessingInstruction)node;
-                target = createProcessingInstruction(source.getTarget(), source.getData());
-                break;
-            }
-            case Node.TEXT_NODE: {
-                Text source = (Text)node;
-                target = createTextNode(source.getData());
-                break;
-            }
-            default: {
-                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone unknown node type " + node.getNodeType() + " (" + node.getClass().getSimpleName() + ")");
-            }
+                return elementCopy;
+
+            case Node.ENTITY_NODE:
+            case Node.NOTATION_NODE:
+                // TODO: implement this when we support these node types
+                throw new UnsupportedOperationException();
+
+            case Node.ENTITY_REFERENCE_NODE:
+                /*
+                 * When we support entities in the doctype, this will need to
+                 * behave differently for clones vs. imports. Clones copy
+                 * entities by value, copying the referenced subtree from the
+                 * original document. Imports copy entities by reference,
+                 * possibly referring to a different subtree in the new
+                 * document.
+                 */
+                return createEntityReference(node.getNodeName());
+
+            case Node.PROCESSING_INSTRUCTION_NODE:
+                ProcessingInstruction pi = (ProcessingInstruction) node;
+                return createProcessingInstruction(pi.getTarget(), pi.getData());
+
+            case Node.TEXT_NODE:
+                return createTextNode(((Text) node).getData());
+
+            default:
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+                        "Unsupported node type " + node.getNodeType());
         }
+    }
+
+    /**
+     * Returns a copy of the given node or subtree with this document as its
+     * owner.
+     *
+     * @param operation either {@link UserDataHandler#NODE_CLONED} or
+     *      {@link UserDataHandler#NODE_IMPORTED}.
+     * @param node a node belonging to any document or DOM implementation.
+     * @param deep true to recursively copy any child nodes; false to do no such
+     *      copying and return a node with no children.
+     */
+    Node cloneOrImportNode(short operation, Node node, boolean deep) {
+        NodeImpl copy = shallowCopy(operation, node);
 
         if (deep) {
             NodeList list = node.getChildNodes();
             for (int i = 0; i < list.getLength(); i++) {
-                Node child = cloneNode(list.item(i), deep);
-                target.appendChild(child);
+                copy.appendChild(cloneOrImportNode(operation, list.item(i), deep));
             }
         }
 
-        notifyUserDataHandlers(UserDataHandler.NODE_CLONED, node, target);
-
-        return target;
+        notifyUserDataHandlers(operation, node, copy);
+        return copy;
     }
 
-    public AttrImpl createAttribute(String name) throws DOMException {
+    public Node importNode(Node importedNode, boolean deep) {
+        return cloneOrImportNode(UserDataHandler.NODE_IMPORTED, importedNode, deep);
+    }
+
+    /**
+     * Detaches the node from its parent (if any) and changes its document to
+     * this document. The node's subtree and attributes will remain attached,
+     * but their document will be changed to this document.
+     */
+    public Node adoptNode(Node node) {
+        if (!(node instanceof NodeImpl)) {
+            return null; // the API specifies this quiet failure
+        }
+        NodeImpl nodeImpl = (NodeImpl) node;
+        switch (nodeImpl.getNodeType()) {
+            case Node.ATTRIBUTE_NODE:
+                AttrImpl attr = (AttrImpl) node;
+                if (attr.ownerElement != null) {
+                    attr.ownerElement.removeAttributeNode(attr);
+                }
+                break;
+
+            case Node.DOCUMENT_FRAGMENT_NODE:
+            case Node.ENTITY_REFERENCE_NODE:
+            case Node.PROCESSING_INSTRUCTION_NODE:
+            case Node.TEXT_NODE:
+            case Node.CDATA_SECTION_NODE:
+            case Node.COMMENT_NODE:
+            case Node.ELEMENT_NODE:
+                break;
+
+            case Node.DOCUMENT_NODE:
+            case Node.DOCUMENT_TYPE_NODE:
+            case Node.ENTITY_NODE:
+            case Node.NOTATION_NODE:
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+                        "Cannot adopt nodes of type " + nodeImpl.getNodeType());
+
+            default:
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+                        "Unsupported node type " + node.getNodeType());
+        }
+
+        Node parent = nodeImpl.getParentNode();
+        if (parent != null) {
+            parent.removeChild(nodeImpl);
+        }
+
+        changeDocumentToThis(nodeImpl);
+        notifyUserDataHandlers(UserDataHandler.NODE_ADOPTED, node, null);
+        return nodeImpl;
+    }
+
+    /**
+     * Recursively change the document of {@code node} without also changing its
+     * parent node. Only adoptNode() should invoke this method, otherwise nodes
+     * will be left in an inconsistent state.
+     */
+    private void changeDocumentToThis(NodeImpl node) {
+        Map<String, UserData> userData = node.document.getUserDataMapForRead(node);
+        if (!userData.isEmpty()) {
+            getUserDataMap(node).putAll(userData);
+        }
+        node.document = this;
+
+        // change the document on all child nodes
+        NodeList list = node.getChildNodes();
+        for (int i = 0; i < list.getLength(); i++) {
+            changeDocumentToThis((NodeImpl) list.item(i));
+        }
+
+        // change the document on all attribute nodes
+        if (node.getNodeType() == Node.ELEMENT_NODE) {
+            NamedNodeMap attributes = node.getAttributes();
+            for (int i = 0; i < attributes.getLength(); i++) {
+                changeDocumentToThis((AttrImpl) attributes.item(i));
+            }
+        }
+    }
+
+    public AttrImpl createAttribute(String name) {
         return new AttrImpl(this, name);
     }
 
-    public Attr createAttributeNS(String namespaceURI, String qualifiedName)
-            throws DOMException {
+    public AttrImpl createAttributeNS(String namespaceURI, String qualifiedName) {
         return new AttrImpl(this, namespaceURI, qualifiedName);
     }
 
-    public CDATASection createCDATASection(String data) throws DOMException {
+    public CDATASectionImpl createCDATASection(String data) {
         return new CDATASectionImpl(this, data);
     }
 
-    public Comment createComment(String data) {
+    public CommentImpl createComment(String data) {
         return new CommentImpl(this, data);
     }
 
-    public DocumentFragment createDocumentFragment() {
+    public DocumentFragmentImpl createDocumentFragment() {
         return new DocumentFragmentImpl(this);
     }
 
-    public Element createElement(String tagName) throws DOMException {
+    public ElementImpl createElement(String tagName) {
         return new ElementImpl(this, tagName);
     }
 
-    public Element createElementNS(String namespaceURI, String qualifiedName)
-            throws DOMException {
+    public ElementImpl createElementNS(String namespaceURI, String qualifiedName) {
         return new ElementImpl(this, namespaceURI, qualifiedName);
     }
 
-    public EntityReference createEntityReference(String name)
-            throws DOMException {
+    public EntityReferenceImpl createEntityReference(String name) {
         return new EntityReferenceImpl(this, name);
     }
 
-    public ProcessingInstruction createProcessingInstruction(String target,
-            String data) throws DOMException {
+    public ProcessingInstructionImpl createProcessingInstruction(String target, String data) {
         return new ProcessingInstructionImpl(this, target, data);
     }
 
-    public Text createTextNode(String data) {
+    public TextImpl createTextNode(String data) {
         return new TextImpl(this, data);
     }
 
     public DocumentType getDoctype() {
-        for (int i = 0; i < children.size(); i++) {
-            if (children.get(i) instanceof DocumentType) {
-                return (DocumentType) children.get(i);
+        for (LeafNodeImpl child : children) {
+            if (child instanceof DocumentType) {
+                return (DocumentType) child;
             }
         }
 
@@ -268,9 +350,9 @@
     }
 
     public Element getDocumentElement() {
-        for (int i = 0; i < children.size(); i++) {
-            if (children.get(i) instanceof Element) {
-                return (Element) children.get(i);
+        for (LeafNodeImpl child : children) {
+            if (child instanceof Element) {
+                return (Element) child;
             }
         }
 
@@ -311,13 +393,8 @@
         return Node.DOCUMENT_NODE;
     }
 
-    public Node importNode(Node importedNode, boolean deep) throws DOMException {
-        // TODO: callback the UserDataHandler with a NODE_IMPORTED event
-        return cloneNode(importedNode, deep);
-    }
-
     @Override
-    public Node insertChildAt(Node newChild, int index) throws DOMException {
+    public Node insertChildAt(Node newChild, int index) {
         // Make sure we have at most one root element and one DTD element.
         if (newChild instanceof Element && getDocumentElement() != null) {
             throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
@@ -330,7 +407,7 @@
         return super.insertChildAt(newChild, index);
     }
 
-    @Override public String getTextContent() throws DOMException {
+    @Override public String getTextContent() {
         return null;
     }
 
@@ -346,7 +423,7 @@
         return xmlStandalone;
     }
 
-    public void setXmlStandalone(boolean xmlStandalone) throws DOMException {
+    public void setXmlStandalone(boolean xmlStandalone) {
         this.xmlStandalone = xmlStandalone;
     }
 
@@ -354,7 +431,7 @@
         return xmlVersion;
     }
 
-    public void setXmlVersion(String xmlVersion) throws DOMException {
+    public void setXmlVersion(String xmlVersion) {
         this.xmlVersion = xmlVersion;
     }
 
@@ -374,11 +451,6 @@
         this.documentUri = documentUri;
     }
 
-    public Node adoptNode(Node source) throws DOMException {
-        // TODO: callback the UserDataHandler with a NODE_ADOPTED event
-        throw new UnsupportedOperationException(); // TODO
-    }
-
     public DOMConfiguration getDomConfig() {
         if (domConfiguration == null) {
             domConfiguration = new DOMConfigurationImpl();
@@ -395,8 +467,7 @@
         ((DOMConfigurationImpl) getDomConfig()).normalize(root);
     }
 
-    public Node renameNode(Node n, String namespaceURI, String qualifiedName)
-            throws DOMException {
+    public Node renameNode(Node n, String namespaceURI, String qualifiedName) {
         // TODO: callback the UserDataHandler with a NODE_RENAMED event
         throw new UnsupportedOperationException(); // TODO
     }
@@ -405,9 +476,9 @@
      * Returns a map with the user data objects attached to the specified node.
      * This map is readable and writable.
      */
-    Map<String, UserData> getUserDataMap(Node node) {
+    Map<String, UserData> getUserDataMap(NodeImpl node) {
         if (nodeToUserData == null) {
-            nodeToUserData = new WeakHashMap<Node, Map<String, UserData>>();
+            nodeToUserData = new WeakHashMap<NodeImpl, Map<String, UserData>>();
         }
         Map<String, UserData> userDataMap = nodeToUserData.get(node);
         if (userDataMap == null) {
@@ -421,7 +492,7 @@
      * Returns a map with the user data objects attached to the specified node.
      * The returned map may be read-only.
      */
-    Map<String, UserData> getUserDataMapForRead(Node node) {
+    Map<String, UserData> getUserDataMapForRead(NodeImpl node) {
         if (nodeToUserData == null) {
             return Collections.emptyMap();
         }
@@ -434,13 +505,28 @@
     /**
      * Calls {@link UserDataHandler#handle} on each of the source node's
      * value/handler pairs.
+     *
+     * <p>If the source node comes from another DOM implementation, user data
+     * handlers will <strong>not</strong> be notified. The DOM API provides no
+     * mechanism to inspect a foreign node's user data.
      */
-    private void notifyUserDataHandlers(short operation, Node src, Node dst) {
-        for (Map.Entry<String, UserData> entry : getUserDataMapForRead(src).entrySet()) {
+    private static void notifyUserDataHandlers(
+            short operation, Node source, NodeImpl destination) {
+        if (!(source instanceof NodeImpl)) {
+            return;
+        }
+
+        NodeImpl srcImpl = (NodeImpl) source;
+        if (srcImpl.document == null) {
+            return;
+        }
+
+        for (Map.Entry<String, UserData> entry
+                : srcImpl.document.getUserDataMapForRead(srcImpl).entrySet()) {
             UserData userData = entry.getValue();
             if (userData.handler != null) {
                 userData.handler.handle(
-                        operation, entry.getKey(), userData.value, src, dst);
+                        operation, entry.getKey(), userData.value, source, destination);
             }
         }
     }
diff --git a/libcore/xml/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java b/libcore/xml/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java
index e272a3e..c3e5a2e 100644
--- a/libcore/xml/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java
+++ b/libcore/xml/src/main/java/org/apache/harmony/xml/dom/ElementImpl.java
@@ -136,7 +136,7 @@
         return attr.getValue();
     }
 
-    public Attr getAttributeNode(String name) {
+    public AttrImpl getAttributeNode(String name) {
         int i = indexOfAttribute(name);
         
         if (i == -1) {
@@ -146,7 +146,7 @@
         return attributes.get(i);
     }
 
-    public Attr getAttributeNodeNS(String namespaceURI, String localName) {
+    public AttrImpl getAttributeNodeNS(String namespaceURI, String localName) {
         int i = indexOfAttributeNS(namespaceURI, localName);
         
         if (i == -1) {
@@ -160,8 +160,25 @@
     public NamedNodeMap getAttributes() {
         return new ElementAttrNamedNodeMapImpl();
     }
-    
+
+    /**
+     * This implementation walks the entire document looking for an element
+     * with the given ID attribute. We should consider adding an index to speed
+     * navigation of large documents.
+     */
     Element getElementById(String name) {
+        for (Attr attr : attributes) {
+            if (attr.isId() && name.equals(attr.getValue())) {
+                return this;
+            }
+        }
+
+        /*
+         * TODO: Remove this behavior.
+         * The spec explicitly says that this is a bad idea. From
+         * Document.getElementById(): "Attributes with the name "ID"
+         * or "id" are not of type ID unless so defined.
+         */
         if (name.equals(getAttribute("id"))) {
             return this;
         }
@@ -432,20 +449,30 @@
     }
 
     public TypeInfo getSchemaTypeInfo() {
-        throw new UnsupportedOperationException(); // TODO
+        // TODO: populate this when we support XML Schema
+        return NULL_TYPE_INFO;
     }
 
     public void setIdAttribute(String name, boolean isId) throws DOMException {
-        throw new UnsupportedOperationException(); // TODO
+        AttrImpl attr = getAttributeNode(name);
+        if (attr == null) {
+            throw new DOMException(DOMException.NOT_FOUND_ERR,
+                    "No such attribute: " + name);
+        }
+        attr.isId = isId;
     }
 
     public void setIdAttributeNS(String namespaceURI, String localName,
             boolean isId) throws DOMException {
-        throw new UnsupportedOperationException(); // TODO
+        AttrImpl attr = getAttributeNodeNS(namespaceURI, localName);
+        if (attr == null) {
+            throw new DOMException(DOMException.NOT_FOUND_ERR,
+                    "No such attribute: " + namespaceURI +  " " + localName);
+        }
+        attr.isId = isId;
     }
 
-    public void setIdAttributeNode(Attr idAttr, boolean isId)
-            throws DOMException {
-        throw new UnsupportedOperationException(); // TODO
+    public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException {
+        ((AttrImpl) idAttr).isId = isId;
     }
 }
diff --git a/libcore/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java b/libcore/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
index 8376689..359a042 100644
--- a/libcore/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
+++ b/libcore/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
@@ -16,6 +16,8 @@
 
 package org.apache.harmony.xml.dom;
 
+import org.apache.xml.serializer.utils.SystemIDResolver;
+import org.apache.xml.utils.URI;
 import org.w3c.dom.Attr;
 import org.w3c.dom.CharacterData;
 import org.w3c.dom.DOMException;
@@ -25,8 +27,10 @@
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.TypeInfo;
 import org.w3c.dom.UserDataHandler;
 
+import javax.xml.transform.TransformerException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -45,7 +49,20 @@
 public abstract class NodeImpl implements Node {
 
     private static final NodeList EMPTY_LIST = new NodeListImpl();
-    
+
+    static final TypeInfo NULL_TYPE_INFO = new TypeInfo() {
+        public String getTypeName() {
+            return null;
+        }
+        public String getTypeNamespace() {
+            return null;
+        }
+        public boolean isDerivedFrom(
+                String typeNamespaceArg, String typeNameArg, int derivationMethod) {
+            return false;
+        }
+    };
+
     DocumentImpl document;
 
     NodeImpl(DocumentImpl document) {
@@ -56,8 +73,8 @@
         throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
     }
 
-    public Node cloneNode(boolean deep) {
-        return document.cloneNode(this, deep);
+    public final Node cloneNode(boolean deep) {
+        return document.cloneOrImportNode(UserDataHandler.NODE_CLONED, this, deep);
     }
 
     public NamedNodeMap getAttributes() {
@@ -244,35 +261,83 @@
         return matchesName(namespaceURI, getNamespaceURI(), wildcard) && matchesName(localName, getLocalName(), wildcard);
     }
 
-    public String getBaseURI() {
-        /*
-         * TODO: implement. For reference, here's Xerces' behaviour:
-         *
-         * In all cases, the returned URI should be sanitized before it is
-         * returned. If the URI is malformed, null should be returned instead.
-         *
-         * For document nodes, this should return a member field that's
-         * initialized by the parser.
-         *
-         * For element nodes, this should first look for the xml:base attribute.
-         *   if that exists and is absolute, it should be returned.
-         *   if that exists and is relative, it should be resolved to the parent's base URI
-         *   if it doesn't exist, the parent's baseURI should be returned
-         *
-         * For entity nodes, if a base URI exists that should be returned.
-         * Otherwise the document's base URI should be returned
-         *
-         * For entity references, if a base URI exists that should be returned
-         * otherwise it dereferences the entity (via the document) and uses the
-         * entity's base URI.
-         *
-         * For notations, it returns the base URI field.
-         *
-         * For processing instructions, it returns the parent's base URI.
-         *
-         * For all other node types, it returns null.
-         */
-        return null;
+    public final String getBaseURI() {
+        switch (getNodeType()) {
+            case DOCUMENT_NODE:
+                return sanitizeUri(((Document) this).getDocumentURI());
+
+            case ELEMENT_NODE:
+                Element element = (Element) this;
+                String uri = element.getAttributeNS(
+                        "http://www.w3.org/XML/1998/namespace", "base"); // or "xml:base"
+
+                // if this node has no base URI, return the parent's.
+                if (uri == null || uri.length() == 0) {
+                    return getParentBaseUri();
+                }
+
+                // if this node's URI is absolute, return that
+                if (SystemIDResolver.isAbsoluteURI(uri)) {
+                    return uri;
+                }
+
+                // this node has a relative URI. Try to resolve it against the
+                // parent, but if that doesn't work just give up and return null.
+                String parentUri = getParentBaseUri();
+                if (parentUri == null) {
+                    return null;
+                }
+                try {
+                    return SystemIDResolver.getAbsoluteURI(uri, parentUri);
+                } catch (TransformerException e) {
+                    return null; // the spec requires that we swallow exceptions
+                }
+
+            case PROCESSING_INSTRUCTION_NODE:
+                return getParentBaseUri();
+
+            case NOTATION_NODE:
+            case ENTITY_NODE:
+                // When we support these node types, the parser should
+                // initialize a base URI field on these nodes.
+                return null;
+
+            case ENTITY_REFERENCE_NODE:
+                // TODO: get this value from the parser, falling back to the
+                // referenced entity's baseURI if that doesn't exist
+                return null;
+
+            case DOCUMENT_TYPE_NODE:
+            case DOCUMENT_FRAGMENT_NODE:
+            case ATTRIBUTE_NODE:
+            case TEXT_NODE:
+            case CDATA_SECTION_NODE:
+            case COMMENT_NODE:
+                return null;
+
+            default:
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+                        "Unsupported node type " + getNodeType());
+        }
+    }
+
+    private String getParentBaseUri() {
+        Node parentNode = getParentNode();
+        return parentNode != null ? parentNode.getBaseURI() : null;
+    }
+
+    /**
+     * Returns the sanitized input if it is a URI, or {@code null} otherwise.
+     */
+    private String sanitizeUri(String uri) {
+        if (uri == null || uri.length() == 0) {
+            return null;
+        }
+        try {
+            return new URI(uri).toString();
+        } catch (URI.MalformedURIException e) {
+            return null;
+        }
     }
 
     public short compareDocumentPosition(Node other)
diff --git a/libcore/xml/src/test/java/tests/xml/DomTest.java b/libcore/xml/src/test/java/tests/xml/DomTest.java
index 0bb27dc..3bafb78 100644
--- a/libcore/xml/src/test/java/tests/xml/DomTest.java
+++ b/libcore/xml/src/test/java/tests/xml/DomTest.java
@@ -16,6 +16,7 @@
 
 package tests.xml;
 
+import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 import org.w3c.dom.Attr;
 import org.w3c.dom.CDATASection;
@@ -27,20 +28,26 @@
 import org.w3c.dom.Element;
 import org.w3c.dom.Entity;
 import org.w3c.dom.EntityReference;
+import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 import org.w3c.dom.Notation;
 import org.w3c.dom.ProcessingInstruction;
 import org.w3c.dom.Text;
+import org.w3c.dom.TypeInfo;
 import org.w3c.dom.UserDataHandler;
 import org.xml.sax.InputSource;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
+import java.io.File;
+import java.io.FileWriter;
 import java.io.StringReader;
 import java.io.StringWriter;
 import java.util.ArrayList;
@@ -48,8 +55,12 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
+import static org.w3c.dom.UserDataHandler.NODE_ADOPTED;
 import static org.w3c.dom.UserDataHandler.NODE_CLONED;
+import static org.w3c.dom.UserDataHandler.NODE_IMPORTED;
 
 /**
  * Construct a DOM and then interrogate it.
@@ -111,6 +122,7 @@
 
     @Override protected void setUp() throws Exception {
         transformer = TransformerFactory.newInstance().newTransformer();
+        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         factory.setNamespaceAware(true);
         builder = factory.newDocumentBuilder();
@@ -817,6 +829,366 @@
         assertEquals(expected, handler.calls);
     }
 
+    /**
+     * A shallow import requires importing the attributes but not the child
+     * nodes.
+     */
+    public void testUserDataHandlerNotifiedOfShallowImports() {
+        RecordingHandler handler = new RecordingHandler();
+        name.setUserData("a", "apple", handler);
+        name.setUserData("b", "banana", handler);
+        standard.setUserData("c", "cat", handler);
+        waffles.setUserData("d", "dog", handler);
+
+        Document newDocument = builder.newDocument();
+        Element importedName = (Element) newDocument.importNode(name, false);
+        Attr importedStandard = importedName.getAttributeNode("a:standard");
+
+        Set<String> expected = new HashSet<String>();
+        expected.add(notification(NODE_IMPORTED, "a", "apple", name, importedName));
+        expected.add(notification(NODE_IMPORTED, "b", "banana", name, importedName));
+        expected.add(notification(NODE_IMPORTED, "c", "cat", standard, importedStandard));
+        assertEquals(expected, handler.calls);
+    }
+
+    /**
+     * A deep import requires cloning both the attributes and the child nodes.
+     */
+    public void testUserDataHandlerNotifiedOfDeepImports() {
+        RecordingHandler handler = new RecordingHandler();
+        name.setUserData("a", "apple", handler);
+        name.setUserData("b", "banana", handler);
+        standard.setUserData("c", "cat", handler);
+        waffles.setUserData("d", "dog", handler);
+
+        Document newDocument = builder.newDocument();
+        Element importedName = (Element) newDocument.importNode(name, true);
+        Attr importedStandard = importedName.getAttributeNode("a:standard");
+        Text importedWaffles = (Text) importedName.getChildNodes().item(0);
+
+        Set<String> expected = new HashSet<String>();
+        expected.add(notification(NODE_IMPORTED, "a", "apple", name, importedName));
+        expected.add(notification(NODE_IMPORTED, "b", "banana", name, importedName));
+        expected.add(notification(NODE_IMPORTED, "c", "cat", standard, importedStandard));
+        expected.add(notification(NODE_IMPORTED, "d", "dog", waffles, importedWaffles));
+        assertEquals(expected, handler.calls);
+    }
+
+    public void testImportNodeDeep() throws TransformerException {
+        String original = domToStringStripElementWhitespace(document);
+
+        Document newDocument = builder.newDocument();
+        Element importedItem = (Element) newDocument.importNode(item, true);
+        assertDetached(item.getParentNode(), importedItem);
+
+        newDocument.appendChild(importedItem);
+        String expected = original.replaceAll("</?menu>", "");
+        assertEquals(expected, domToStringStripElementWhitespace(newDocument));
+    }
+
+    public void testImportNodeShallow() throws TransformerException {
+        Document newDocument = builder.newDocument();
+        Element importedItem = (Element) newDocument.importNode(item, false);
+        assertDetached(item.getParentNode(), importedItem);
+
+        newDocument.appendChild(importedItem);
+        assertEquals("<item xmlns=\"http://food\" xmlns:a=\"http://addons\"/>",
+                domToString(newDocument));
+    }
+
+    public void testNodeAdoption() throws Exception {
+        for (Node node : allNodes) {
+            if (node == document || node == doctype || node == sp || node == png) {
+                assertNotAdoptable(node);
+            } else {
+                adoptAndCheck(node);
+            }
+        }
+    }
+
+    private void assertNotAdoptable(Node node) {
+        try {
+            builder.newDocument().adoptNode(node);
+            fail();
+        } catch (DOMException e) {
+        }
+    }
+
+    /**
+     * Adopts the node into another document, then adopts the root element, and
+     * then attaches the adopted node in the proper place. The net result should
+     * be that the document's entire contents have moved to another document.
+     */
+    private void adoptAndCheck(Node node) throws Exception {
+        String original = domToString(document);
+        Document newDocument = builder.newDocument();
+
+        // remember where to insert the node in the new document
+        boolean isAttribute = node.getNodeType() == Node.ATTRIBUTE_NODE;
+        Node parent = isAttribute
+                ? ((Attr) node).getOwnerElement() : node.getParentNode();
+        Node nextSibling = node.getNextSibling();
+
+        // move the node and make sure it was detached
+        assertSame(node, newDocument.adoptNode(node));
+        assertDetached(parent, node);
+
+        // move the rest of the document and wire the adopted back into place
+        assertSame(menu, newDocument.adoptNode(menu));
+        newDocument.appendChild(menu);
+        if (isAttribute) {
+            ((Element) parent).setAttributeNodeNS((Attr) node);
+        } else if (nextSibling != null) {
+            parent.insertBefore(node, nextSibling);
+        } else if (parent != document) {
+            parent.appendChild(node);
+        }
+
+        assertEquals(original, domToString(newDocument));
+        document = newDocument;
+    }
+
+    private void assertDetached(Node formerParent, Node node) {
+        assertNull(node.getParentNode());
+        NodeList children = formerParent.getChildNodes();
+        for (int i = 0; i < children.getLength(); i++) {
+            assertTrue(children.item(i) != node);
+        }
+        if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
+            assertNull(((Attr) node).getOwnerElement());
+            NamedNodeMap attributes = formerParent.getAttributes();
+            for (int i = 0; i < attributes.getLength(); i++) {
+                assertTrue(attributes.item(i) != node);
+            }
+        }
+    }
+
+    public void testAdoptionImmediatelyAfterParsing() throws Exception {
+        Document newDocument = builder.newDocument();
+        try {
+            assertSame(name, newDocument.adoptNode(name));
+            assertSame(newDocument, name.getOwnerDocument());
+            assertSame(newDocument, standard.getOwnerDocument());
+            assertSame(newDocument, waffles.getOwnerDocument());
+        } catch (Throwable e) {
+            AssertionFailedError failure = new AssertionFailedError(
+                    "This implementation fails to adopt nodes before the "
+                            + "document has been traversed");
+            failure.initCause(e);
+            throw failure;
+        }
+    }
+
+    /**
+     * There should be notifications for adopted node itself but none of its
+     * children. The DOM spec is vague on this, so we're consistent with the RI.
+     */
+    public void testUserDataHandlerNotifiedOfOnlyShallowAdoptions() throws Exception {
+        /*
+         * Force a traversal of the document, otherwise this test may fail for
+         * an unrelated reason on version 5 of the RI. That behavior is
+         * exercised by testAdoptionImmediatelyAfterParsing().
+         */
+        domToString(document);
+
+        RecordingHandler handler = new RecordingHandler();
+        name.setUserData("a", "apple", handler);
+        name.setUserData("b", "banana", handler);
+        standard.setUserData("c", "cat", handler);
+        waffles.setUserData("d", "dog", handler);
+
+        Document newDocument = builder.newDocument();
+        assertSame(name, newDocument.adoptNode(name));
+        assertSame(newDocument, name.getOwnerDocument());
+        assertSame(newDocument, standard.getOwnerDocument());
+        assertSame(newDocument, waffles.getOwnerDocument());
+
+        Set<String> expected = new HashSet<String>();
+        expected.add(notification(NODE_ADOPTED, "a", "apple", name, null));
+        expected.add(notification(NODE_ADOPTED, "b", "banana", name, null));
+        assertEquals(expected, handler.calls);
+    }
+
+    public void testBaseUriRelativeUriResolution() throws Exception {
+        File file = File.createTempFile("DomTest.java", "xml");
+        File parentFile = file.getParentFile();
+        FileWriter writer = new FileWriter(file);
+        writer.write("<a>"
+                + "  <b xml:base=\"b1/b2\">"
+                + "    <c>"
+                + "      <d xml:base=\"../d1/d2\"><e/></d>"
+                + "    </c>"
+                + "  </b>"
+                + "  <h xml:base=\"h1/h2/\">"
+                + "    <i xml:base=\"../i1/i2\"/>"
+                + "  </h>"
+                + "</a>");
+        writer.close();
+        document = builder.parse(file);
+
+        assertFileUriEquals("", file.getPath(), document.getBaseURI());
+        assertFileUriEquals("", file.getPath(), document.getDocumentURI());
+        Element a = document.getDocumentElement();
+        assertFileUriEquals("", file.getPath(), a.getBaseURI());
+
+        String message = "This implementation's getBaseURI() doesn't handle relative URIs";
+        Element b = (Element) a.getChildNodes().item(1);
+        Element c = (Element) b.getChildNodes().item(1);
+        Element d = (Element) c.getChildNodes().item(1);
+        Element e = (Element) d.getChildNodes().item(0);
+        Element h = (Element) a.getChildNodes().item(3);
+        Element i = (Element) h.getChildNodes().item(1);
+        assertFileUriEquals(message, parentFile + "/b1/b2", b.getBaseURI());
+        assertFileUriEquals(message, parentFile + "/b1/b2", c.getBaseURI());
+        assertFileUriEquals(message, parentFile + "/d1/d2", d.getBaseURI());
+        assertFileUriEquals(message, parentFile + "/d1/d2", e.getBaseURI());
+        assertFileUriEquals(message, parentFile + "/h1/h2/", h.getBaseURI());
+        assertFileUriEquals(message, parentFile + "/h1/i1/i2", i.getBaseURI());
+    }
+
+    /**
+     * Regrettably both "file:/tmp/foo.txt" and "file:///tmp/foo.txt" are
+     * legal URIs, and different implementations emit different forms.
+     */
+    private void assertFileUriEquals(
+            String message, String expectedFile, String actual) {
+        if (!("file:" + expectedFile).equals(actual)
+                && !("file://" + expectedFile).equals(actual)) {
+            fail("Expected URI for: " + expectedFile
+                    + " but was " + actual + ". " + message);
+        }
+    }
+
+    /**
+     * According to the <a href="http://www.w3.org/TR/xmlbase/">XML Base</a>
+     * spec, fragments (like "#frag" or "") should not be dereferenced.
+     */
+    public void testBaseUriResolutionWithHashes() throws Exception {
+        document = builder.parse(new InputSource(new StringReader(
+                "<a xml:base=\"http://a1/a2\">"
+                        + "  <b xml:base=\"b1#b2\"/>"
+                        + "  <c xml:base=\"#c1\">"
+                        + "    <d xml:base=\"\"/>"
+                        + "  </c>"
+                        + "  <e xml:base=\"\"/>"
+                        + "</a>")));
+        Element a = document.getDocumentElement();
+        assertEquals("http://a1/a2", a.getBaseURI());
+
+        String message = "This implementation's getBaseURI() doesn't handle "
+                + "relative URIs with hashes";
+        Element b = (Element) a.getChildNodes().item(1);
+        Element c = (Element) a.getChildNodes().item(3);
+        Element d = (Element) c.getChildNodes().item(1);
+        Element e = (Element) a.getChildNodes().item(5);
+        assertEquals(message, "http://a1/b1#b2", b.getBaseURI());
+        assertEquals(message, "http://a1/a2#c1", c.getBaseURI());
+        assertEquals(message, "http://a1/a2#c1", d.getBaseURI());
+        assertEquals(message, "http://a1/a2", e.getBaseURI());
+    }
+
+    public void testBaseUriInheritedForProcessingInstructions() {
+        document.setDocumentURI("http://d1/d2");
+        assertEquals("http://d1/d2", wafflemaker.getBaseURI());
+    }
+
+    public void testBaseUriInheritedForEntities() {
+        if (sp == null) {
+            return;
+        }
+        document.setDocumentURI("http://d1/d2");
+        assertEquals("http://d1/d2", sp.getBaseURI());
+    }
+
+    public void testBaseUriNotInheritedForNotations() {
+        if (png == null) {
+            return;
+        }
+        document.setDocumentURI("http://d1/d2");
+        assertNull(png.getBaseURI());
+    }
+
+    public void testBaseUriNotInheritedForDoctypes() {
+        document.setDocumentURI("http://d1/d2");
+        assertNull(doctype.getBaseURI());
+    }
+
+    public void testBaseUriNotInheritedForAttributes() {
+        document.setDocumentURI("http://d1/d2");
+        assertNull(itemXmlns.getBaseURI());
+        assertNull(itemXmlnsA.getBaseURI());
+        assertNull(standard.getBaseURI());
+        assertNull(vitaminsXmlnsA.getBaseURI());
+    }
+
+    public void testBaseUriNotInheritedForTextsOrCdatas() {
+        document.setDocumentURI("http://d1/d2");
+        assertNull(descriptionText1.getBaseURI());
+        assertNull(descriptionText2.getBaseURI());
+        assertNull(option2Reference.getBaseURI());
+    }
+
+    public void testBaseUriNotInheritedForComments() {
+        document.setDocumentURI("http://d1/d2");
+        assertNull(descriptionText1.getBaseURI());
+        assertNull(descriptionText2.getBaseURI());
+    }
+
+    public void testBaseUriNotInheritedForEntityReferences() {
+        document.setDocumentURI("http://d1/d2");
+        assertNull(option2Reference.getBaseURI());
+    }
+
+    public void testProgrammaticElementIds() {
+        vitaminc.setAttribute("name", "c");
+        assertFalse(vitaminc.getAttributeNode("name").isId());
+        assertNull(document.getElementById("c"));
+
+        // set the ID attribute...
+        vitaminc.setIdAttribute("name", true);
+        assertTrue(vitaminc.getAttributeNode("name").isId());
+        assertSame(vitaminc, document.getElementById("c"));
+
+        // ... and then take it away
+        vitaminc.setIdAttribute("name", false);
+        assertFalse(vitaminc.getAttributeNode("name").isId());
+        assertNull(document.getElementById("c"));
+    }
+
+    public void testMultipleIdsOnOneElement() {
+        vitaminc.setAttribute("name", "c");
+        vitaminc.setIdAttribute("name", true);
+        vitaminc.setAttribute("atc", "a11g");
+        vitaminc.setIdAttribute("atc", true);
+
+        assertTrue(vitaminc.getAttributeNode("name").isId());
+        assertTrue(vitaminc.getAttributeNode("atc").isId());
+        assertSame(vitaminc, document.getElementById("c"));
+        assertSame(vitaminc, document.getElementById("a11g"));
+        assertNull(document.getElementById("g"));
+    }
+
+    public void testAttributeNamedIdIsNotAnIdByDefault() {
+        String message = "This implementation incorrectly interprets the "
+                + "\"id\" attribute as an identifier by default.";
+        vitaminc.setAttribute("id", "c");
+        assertNull(message, document.getElementById("c"));
+    }
+
+    public void testElementTypeInfo() {
+        TypeInfo typeInfo = description.getSchemaTypeInfo();
+        assertNull(typeInfo.getTypeName());
+        assertNull(typeInfo.getTypeNamespace());
+        assertFalse(typeInfo.isDerivedFrom("x", "y", TypeInfo.DERIVATION_UNION));
+    }
+
+    public void testAttributeTypeInfo() {
+        TypeInfo typeInfo = standard.getSchemaTypeInfo();
+        assertNull(typeInfo.getTypeName());
+        assertNull(typeInfo.getTypeNamespace());
+        assertFalse(typeInfo.isDerivedFrom("x", "y", TypeInfo.DERIVATION_UNION));
+    }
+
     private class RecordingHandler implements UserDataHandler {
         final Set<String> calls = new HashSet<String>();
         public void handle(short operation, String key, Object data, Node src, Node dst) {
@@ -831,6 +1203,29 @@
     private String domToString(Document document) throws TransformerException {
         StringWriter writer = new StringWriter();
         transformer.transform(new DOMSource(document), new StreamResult(writer));
-        return writer.toString();
+        String result = writer.toString();
+
+        /*
+         * Hack: swap <name>'s a:standard attribute and deluxe attribute if
+         * they're out of order. Some document transformations reorder the
+         * attributes, which causes pain when we try to use String comparison on
+         * them.
+         */
+        Matcher attributeMatcher = Pattern.compile(" a:standard=\"[^\"]+\"").matcher(result);
+        if (attributeMatcher.find()) {
+            result = result.substring(0, attributeMatcher.start())
+                    + result.substring(attributeMatcher.end());
+            int insertionPoint = result.indexOf(" deluxe=\"");
+            result = result.substring(0, insertionPoint)
+                    + attributeMatcher.group()
+                    + result.substring(insertionPoint);
+        }
+
+        return result;
+    }
+
+    private String domToStringStripElementWhitespace(Document document)
+            throws TransformerException {
+        return domToString(document).replaceAll("(?m)>\\s+<", "><");
     }
 }
diff --git a/libcore/xml/src/test/java/tests/xml/NormalizeTest.java b/libcore/xml/src/test/java/tests/xml/NormalizeTest.java
index 6fa6c97..f35ca10 100644
--- a/libcore/xml/src/test/java/tests/xml/NormalizeTest.java
+++ b/libcore/xml/src/test/java/tests/xml/NormalizeTest.java
@@ -32,6 +32,8 @@
 import org.xml.sax.InputSource;
 
 import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
@@ -588,10 +590,10 @@
 
     private String domToString(Document document) throws TransformerException {
         StringWriter writer = new StringWriter();
-        TransformerFactory.newInstance().newTransformer()
-                .transform(new DOMSource(document), new StreamResult(writer));
-        String xml = writer.toString();
-        return xml.replaceFirst("<\\?xml[^?]*\\?>", "");
+        Transformer transformer = TransformerFactory.newInstance() .newTransformer();
+        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+        transformer.transform(new DOMSource(document), new StreamResult(writer));
+        return writer.toString();
     }
 
     private class ErrorRecorder implements DOMErrorHandler {
diff --git a/tests/083-jit-regressions/expected.txt b/tests/083-jit-regressions/expected.txt
index faf0a7d..1f30d21 100644
--- a/tests/083-jit-regressions/expected.txt
+++ b/tests/083-jit-regressions/expected.txt
@@ -1,2 +1,3 @@
-b2296099 Passes
+b2296099 passes
 b2302318 passes
+b2487514 passes
diff --git a/tests/083-jit-regressions/info.txt b/tests/083-jit-regressions/info.txt
index 42d3cd9..b791aba 100644
--- a/tests/083-jit-regressions/info.txt
+++ b/tests/083-jit-regressions/info.txt
@@ -5,4 +5,6 @@
 
 This test covers JIT regressions
 
-http://b/issue?id=2296099 JIT shift bug
+2296099 JIT shift bug
+2302318 Crash during spin-on-suspend testing
+2487514 Missed exception in PriorityBlockingQueueTest.testToArray1_BadArg
diff --git a/tests/083-jit-regressions/src/Main.java b/tests/083-jit-regressions/src/Main.java
index 1e91299..1f1dee3 100644
--- a/tests/083-jit-regressions/src/Main.java
+++ b/tests/083-jit-regressions/src/Main.java
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+import java.util.concurrent.*;
+
 /**
  * Test for Jit regressions.
  */
@@ -21,6 +23,7 @@
     public static void main(String args[]) throws Exception {
         b2296099Test();
         b2302318Test();
+        b2487514Test();
     }
 
     static void b2296099Test() throws Exception {
@@ -41,7 +44,7 @@
                throw new RuntimeException("Unexpected value: " + bl
                        + " after " + i + " iterations");
        }
-       System.out.println("b2296099 Passes");
+       System.out.println("b2296099 passes");
    }
 
     static int rotateLeft(int i, int distance) {
@@ -69,6 +72,39 @@
 
         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)");
+        }
+    }
 }
 
 class SpinThread extends Thread {
diff --git a/tools/gdbjithelper/gdbjithelper.c b/tools/gdbjithelper/gdbjithelper.c
index d0f9ce3..862fcae 100644
--- a/tools/gdbjithelper/gdbjithelper.c
+++ b/tools/gdbjithelper/gdbjithelper.c
@@ -16,6 +16,11 @@
 
 #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;
 
@@ -63,22 +68,39 @@
     0x4284aa7a, 0xf927f7b7, 0x40112268, 0x419da7f8,
 };
 
-void dumpCode()
+/* 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 < sizeof(codePC)/sizeof(int); i++) {
-        printf("codePC[%d]: %#x\n", i, codePC[i]);
+    for (i = 0; i < NUM_DUMPED_WORDS; i++) {
+        printf("%p codePC[%d]: %#010x\n", pc + i, i, pc[i]);
     }
 
-    for (i = 0; i < sizeof(codeLR)/sizeof(int); i++) {
-        printf("codeLR[%d]: %#x\n", i, codeLR[i]);
+    for (i = 0; i < NUM_DUMPED_WORDS; i++) {
+        printf("%p codeLR[%d]: %#010x\n", lr + i, i, lr[i]);
     }
 }
 
 int main()
 {
-    dumpCode();
+    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);
     }
diff --git a/vm/CheckJni.c b/vm/CheckJni.c
index ff0efd3..c43b1c6 100644
--- a/vm/CheckJni.c
+++ b/vm/CheckJni.c
@@ -804,7 +804,7 @@
 static void checkStaticFieldID(JNIEnv* env, jclass jclazz, jfieldID fieldID)
 {
     ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
-    StaticField* base = clazz->sfields;
+    StaticField* base = &clazz->sfields[0];
     int fieldCount = clazz->sfieldCount;
 
     if ((StaticField*) fieldID < base ||
diff --git a/vm/SignalCatcher.c b/vm/SignalCatcher.c
index 7edbf38..d3b35b6 100644
--- a/vm/SignalCatcher.c
+++ b/vm/SignalCatcher.c
@@ -13,6 +13,7 @@
  * 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
@@ -29,6 +30,8 @@
 #include <fcntl.h>
 #include <errno.h>
 
+#include <cutils/open_memstream.h>
+
 static void* signalCatcherThreadStart(void* arg);
 
 /*
@@ -93,87 +96,150 @@
 }
 
 /*
- * Dump the stack traces for all threads to the log or to a file.  If it's
- * to a file we have a little setup to do.
+ * Dump the stack traces for all threads to the supplied file, putting
+ * a timestamp header on it.
  */
-static void logThreadStacks(void)
+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(void)
+{
+    char* traceBuf = NULL;
+    size_t traceLen;
+
+    dvmSuspendAllThreads(SUSPEND_FOR_STACK_DUMP);
+
+    dvmDumpLoaderStats("sig");
+
     if (gDvm.stackTraceFile == NULL) {
-        /* just dump to log file */
+        /* just dump to log */
+        DebugOutputTarget target;
         dvmCreateLogOutputTarget(&target, ANDROID_LOG_INFO, LOG_TAG);
         dvmDumpAllThreadsEx(&target, true);
     } else {
-        FILE* fp = NULL;
-        int cc, fd;
+        /* write to memory buffer */
+        FILE* memfp = open_memstream(&traceBuf, &traceLen);
+        if (memfp == NULL) {
+            LOGE("Unable to create memstream for stack traces\n");
+            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) {
+        dvmLockMutex(&gDvm.jniGlobalRefLock);
+        dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
+        dvmUnlockMutex(&gDvm.jniGlobalRefLock);
+    }
+    if (false) dvmDumpTrackedAllocations(true);
+
+    dvmResumeAllThreads(SUSPEND_FOR_STACK_DUMP);
+
+    if (traceBuf != NULL) {
         /*
          * Open the stack trace output file, creating it if necessary.  It
          * needs to be world-writable so other processes can write to it.
          */
-        fd = open(gDvm.stackTraceFile, O_WRONLY | O_APPEND | O_CREAT, 0666);
+        int fd = open(gDvm.stackTraceFile, O_WRONLY | O_APPEND | O_CREAT, 0666);
         if (fd < 0) {
             LOGE("Unable to open stack trace file '%s': %s\n",
                 gDvm.stackTraceFile, strerror(errno));
-            return;
-        }
-
-        /* gain exclusive access to the file */
-        cc = flock(fd, LOCK_EX | LOCK_UN);
-        if (cc != 0) {
-            LOGV("Sleeping on flock(%s)\n", gDvm.stackTraceFile);
-            cc = flock(fd, LOCK_EX);
-        }
-        if (cc != 0) {
-            LOGE("Unable to lock stack trace file '%s': %s\n",
-                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\n",
+                    gDvm.stackTraceFile, (int) actual, traceLen,
+                    strerror(errno));
+            } else {
+                LOGI("Wrote stack traces to '%s'\n", gDvm.stackTraceFile);
+            }
             close(fd);
-            return;
         }
 
-        fp = fdopen(fd, "a");
-        if (fp == NULL) {
-            LOGE("Unable to fdopen '%s' (%d): %s\n",
-                gDvm.stackTraceFile, fd, strerror(errno));
-            flock(fd, LOCK_UN);
-            close(fd);
-            return;
-        }
-
-        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");
-        fflush(fp);     /* emit at least the header if we crash during dump */
-        dvmDumpAllThreadsEx(&target, true);
-        fprintf(fp, "----- end %d -----\n", pid);
-
-        /*
-         * Unlock and close the file, flushing pending data before we unlock
-         * it.  The fclose() will close the underyling fd.
-         */
-        fflush(fp);
-        flock(fd, LOCK_UN);
-        fclose(fp);
-
-        LOGI("Wrote stack trace to '%s'\n", gDvm.stackTraceFile);
+        free(traceBuf);
     }
 }
 
+/*
+ * Respond to a SIGUSR1 by forcing a GC.  If we were built with HPROF
+ * support, generate an HPROF dump file.
+ *
+ * (The HPROF dump generation is not all that useful now that we have
+ * better ways to generate it.  Consider removing this in a future release.)
+ */
+static void handleSigUsr1(void)
+{
+#if WITH_HPROF
+    LOGI("SIGUSR1 forcing GC and HPROF dump\n");
+    hprofDumpHeap(NULL, false);
+#else
+    LOGI("SIGUSR1 forcing GC (no HPROF)\n");
+    dvmCollectGarbage(false);
+#endif
+}
+
+#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
+/*
+ * Respond to a SIGUSR2 by dumping some JIT stats and possibly resetting
+ * the code cache.
+ */
+static void handleSigUsr2(void)
+{
+    static int codeCacheResetCount = 0;
+    if ((--codeCacheResetCount & 7) == 0) {
+        gDvmJit.codeCacheFull = true;
+    } else {
+        dvmCompilerDumpStats();
+        /* Stress-test unchain all */
+        dvmJitUnchainAll();
+        LOGD("Send %d more signals to rest the code cache",
+             codeCacheResetCount & 7);
+    }
+}
+#endif
 
 /*
  * Sleep in sigwait() until a signal arrives.
@@ -207,11 +273,8 @@
          * is met.  When the signal hits, we wake up, without any signal
          * handlers being invoked.
          *
-         * We want to suspend all other threads, so that it's safe to
-         * traverse their stacks.
-         *
-         * When running under GDB we occasionally return with EINTR (e.g.
-         * when other threads exit).
+         * When running under GDB we occasionally return from sigwait()
+         * with EINTR (e.g. when other threads exit).
          */
 loop:
         cc = sigwait(&mask, &rcvd);
@@ -234,47 +297,21 @@
         if (gDvm.haltSignalCatcher)
             break;
 
-        if (rcvd == SIGQUIT) {
-            dvmSuspendAllThreads(SUSPEND_FOR_STACK_DUMP);
-            dvmDumpLoaderStats("sig");
-
-            logThreadStacks();
-
+        switch (rcvd) {
+        case SIGQUIT:
+            handleSigQuit();
+            break;
+        case SIGUSR1:
+            handleSigUsr1();
+            break;
 #if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
-            dvmCompilerDumpStats();
+        case SIGUSR2:
+            handleSigUsr2();
+            break;
 #endif
-
-            if (false) {
-                dvmLockMutex(&gDvm.jniGlobalRefLock);
-                //dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
-                dvmUnlockMutex(&gDvm.jniGlobalRefLock);
-            }
-
-            //dvmDumpTrackedAllocations(true);
-            dvmResumeAllThreads(SUSPEND_FOR_STACK_DUMP);
-        } else if (rcvd == SIGUSR1) {
-#if WITH_HPROF
-            LOGI("SIGUSR1 forcing GC and HPROF dump\n");
-            hprofDumpHeap(NULL, false);
-#else
-            LOGI("SIGUSR1 forcing GC (no HPROF)\n");
-            dvmCollectGarbage(false);
-#endif
-#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
-        } else if (rcvd == SIGUSR2) {
-            static int codeCacheResetCount = 0;
-            if ((--codeCacheResetCount & 7) == 0) {
-                gDvmJit.codeCacheFull = true;
-            } else {
-                dvmCompilerDumpStats();
-                /* Stress-test unchain all */
-                dvmJitUnchainAll();
-                LOGD("Send %d more signals to rest the code cache",
-                     codeCacheResetCount & 7);
-            }
-#endif
-        } else {
+        default:
             LOGE("unexpected signal %d\n", rcvd);
+            break;
         }
     }
 
diff --git a/vm/Sync.c b/vm/Sync.c
index e6ef266..fba40e2 100644
--- a/vm/Sync.c
+++ b/vm/Sync.c
@@ -258,6 +258,21 @@
 }
 
 /*
+ * 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.
  */
@@ -770,6 +785,32 @@
 }
 
 /*
+ * 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. */
+    MEM_BARRIER();
+    obj->lock = thin;
+}
+
+/*
  * Implements monitorenter for "synchronized" stuff.
  *
  * This does not fail or throw an exception (unless deadlock prediction
@@ -777,71 +818,85 @@
  */
 void dvmLockObject(Thread* self, Object *obj)
 {
-    volatile u4 *thinp = &obj->lock;
-    u4 hashState;
-    u4 thin;
-    u4 threadId = self->threadId;
-    Monitor *mon;
+    volatile u4 *thinp;
+    ThreadStatus oldStatus;
+    useconds_t sleepDelay;
+    const useconds_t maxSleepDelay = 1 << 20;
+    u4 thin, newThin, threadId;
 
-    /* First, try to grab the lock as if it's thin;
-     * this is the common case and will usually succeed.
-     */
-    hashState = LW_HASH_STATE(*thinp) << LW_HASH_STATE_SHIFT;
-    thin = threadId << LW_LOCK_OWNER_SHIFT;
-    thin |= hashState;
-    if (!ATOMIC_CMP_SWAP((int32_t *)thinp,
-                         hashState,
-                         (int32_t)thin)) {
-        /* The lock is either a thin lock held by someone (possibly 'self'),
-         * or a fat lock.
+    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(*thinp) == threadId) {
-            /* 'self' is already holding the thin lock; we can just
-             * bump the count.  Atomic operations are not necessary
-             * because only the thread holding the lock is allowed
-             * to modify the Lock field.
+        if (LW_LOCK_OWNER(thin) == threadId) {
+            /*
+             * The calling thread owns the lock.  Increment the
+             * value of the recursion count field.
              */
-            *thinp += 1 << LW_LOCK_COUNT_SHIFT;
+            obj->lock += 1 << LW_LOCK_COUNT_SHIFT;
+        } 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 (!ATOMIC_CMP_SWAP((int32_t *)thinp, thin, newThin)) {
+                /*
+                 * The acquire failed.  Try again.
+                 */
+                goto retry;
+            }
         } else {
-            /* If this is a thin lock we need to spin on it, if it's fat
-             * we need to acquire the monitor.
+            LOG_THIN("(%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.
              */
-            if (LW_SHAPE(*thinp) == LW_SHAPE_THIN) {
-                ThreadStatus oldStatus;
-                static const unsigned long maxSleepDelay = 1 * 1024 * 1024;
-                unsigned long sleepDelay;
-
-                LOG_THIN("(%d) spin on lock 0x%08x: 0x%08x (0x%08x) 0x%08x\n",
-                         threadId, (uint)&obj->lock,
-                         hashState, *thinp, thin);
-
-                /* The lock is still thin, but some other thread is
-                 * holding it.  Let the VM know that we're about
-                 * to wait on another thread.
+            oldStatus = dvmChangeStatus(self, THREAD_MONITOR);
+            /*
+             * Spin until the thin lock is released or inflated.
+             */
+            sleepDelay = 0;
+            for (;;) {
+                thin = *thinp;
+                /*
+                 * Check the shape of the lock word.  Another thread
+                 * may have inflated the lock while we were waiting.
                  */
-                oldStatus = dvmChangeStatus(self, THREAD_MONITOR);
-
-                /* Spin until the other thread lets go.
-                 */
-                sleepDelay = 0;
-                do {
-                    /* In addition to looking for an unlock,
-                     * we need to watch out for some other thread
-                     * fattening the lock behind our back.
-                     */
-                    while (LW_LOCK_OWNER(*thinp) != 0) {
-                        if (LW_SHAPE(*thinp) == LW_SHAPE_FAT) {
-                            /* The lock has been fattened already.
+                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 (ATOMIC_CMP_SWAP((int32_t *)thinp,
+                                            thin, newThin)) {
+                            /*
+                             * The acquire succeed.  Break out of the
+                             * loop and proceed to inflate the lock.
                              */
-                            LOG_THIN("(%d) lock 0x%08x surprise-fattened\n",
-                                     threadId, (uint)&obj->lock);
-                            dvmChangeStatus(self, oldStatus);
-                            goto fat_lock;
+                            break;
                         }
-
+                    } else {
+                        /*
+                         * The lock has not been released.  Yield so
+                         * the owning thread can run.
+                         */
                         if (sleepDelay == 0) {
                             sched_yield();
-                            sleepDelay = 1 * 1000;
+                            sleepDelay = 1000;
                         } else {
                             usleep(sleepDelay);
                             if (sleepDelay < maxSleepDelay / 2) {
@@ -849,46 +904,38 @@
                             }
                         }
                     }
-                    hashState = LW_HASH_STATE(*thinp) << LW_HASH_STATE_SHIFT;
-                    thin = threadId << LW_LOCK_OWNER_SHIFT;
-                    thin |= hashState;
-                } while (!ATOMIC_CMP_SWAP((int32_t *)thinp,
-                                          (int32_t)hashState,
-                                          (int32_t)thin));
-                LOG_THIN("(%d) spin on lock done 0x%08x: "
-                         "0x%08x (0x%08x) 0x%08x\n",
-                         threadId, (uint)&obj->lock,
-                         hashState, *thinp, thin);
-
-                /* We've got the thin lock; let the VM know that we're
-                 * done waiting.
-                 */
-                dvmChangeStatus(self, oldStatus);
-
-                /* Fatten the lock.  Note this relinquishes ownership.
-                 * We could also create the monitor in an "owned" state
-                 * to avoid "re-locking" it in fat_lock.
-                 */
-                mon = dvmCreateMonitor(obj);
-                hashState = LW_HASH_STATE(*thinp) << LW_HASH_STATE_SHIFT;
-                obj->lock = (u4)mon | hashState | LW_SHAPE_FAT;
-                LOG_THIN("(%d) lock 0x%08x fattened\n",
-                         threadId, (uint)&obj->lock);
-
-                /* Fall through to acquire the newly fat lock.
-                 */
+                } else {
+                    /*
+                     * The thin lock was inflated by another thread.
+                     * Let the VM know we are no longer waiting and
+                     * try again.
+                     */
+                    LOG_THIN("(%d) lock %p surprise-fattened",
+                             threadId, &obj->lock);
+                    dvmChangeStatus(self, oldStatus);
+                    goto retry;
+                }
             }
-
-            /* The lock is already fat, which means
-             * that obj->lock is a regular (Monitor *).
+            LOG_THIN("(%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.
              */
-        fat_lock:
-            assert(LW_MONITOR(obj->lock) != NULL);
-            lockMonitor(self, LW_MONITOR(obj->lock));
+            dvmChangeStatus(self, oldStatus);
+            /*
+             * Fatten the lock.
+             */
+            inflateMonitor(self, obj);
+            LOG_THIN("(%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));
     }
-    // else, the lock was acquired with the ATOMIC_CMP_SWAP().
-
 #ifdef WITH_DEADLOCK_PREDICTION
     /*
      * See if we were allowed to grab the lock at this time.  We do it
@@ -948,19 +995,16 @@
  */
 bool dvmUnlockObject(Thread* self, Object *obj)
 {
-    volatile u4 *thinp;
     u4 thin;
 
     assert(self != NULL);
     assert(self->status == THREAD_RUNNING);
     assert(obj != NULL);
-
-    thinp = &obj->lock;
     /*
      * Cache the lock word as its value can change while we are
      * examining its state.
      */
-    thin = *thinp;
+    thin = obj->lock;
     if (LW_SHAPE(thin) == LW_SHAPE_THIN) {
         /*
          * The lock is thin.  We must ensure that the lock is owned
@@ -977,13 +1021,13 @@
                  * case.  Unlock by clearing all bits except for the
                  * hash state.
                  */
-                *thinp &= (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT);
+                obj->lock &= (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT);
             } else {
                 /*
                  * The object was recursively acquired.  Decrement the
                  * lock recursion count field.
                  */
-                *thinp -= 1 << LW_LOCK_COUNT_SHIFT;
+                obj->lock -= 1 << LW_LOCK_COUNT_SHIFT;
             }
         } else {
             /*
@@ -1024,8 +1068,7 @@
 void dvmObjectWait(Thread* self, Object *obj, s8 msec, s4 nsec,
     bool interruptShouldThrow)
 {
-    Monitor* mon = LW_MONITOR(obj->lock);
-    u4 hashState;
+    Monitor* mon;
     u4 thin = obj->lock;
 
     /* If the lock is still thin, we need to fatten it.
@@ -1044,24 +1087,11 @@
          * field yet, because 'self' needs to acquire the lock before
          * any other thread gets a chance.
          */
-        mon = dvmCreateMonitor(obj);
-
-        /* 'self' has actually locked the object one or more times;
-         * make sure that the monitor reflects this.
-         */
-        lockMonitor(self, mon);
-        mon->lockCount = LW_LOCK_COUNT(thin);
-        LOG_THIN("(%d) lock 0x%08x fattened by wait() to count %d\n",
-                 self->threadId, (uint)&obj->lock, mon->lockCount);
-
-
-        /* Make the monitor public now that it's in the right state.
-         */
-        MEM_BARRIER();
-        hashState = LW_HASH_STATE(thin) << LW_HASH_STATE_SHIFT;
-        obj->lock = (u4)mon | hashState | LW_SHAPE_FAT;
+        inflateMonitor(self, obj);
+        LOG_THIN("(%d) lock %p fattened by wait() to count %d",
+                 self->threadId, &obj->lock, mon->lockCount);
     }
-
+    mon = LW_MONITOR(obj->lock);
     waitMonitor(self, mon, msec, nsec, interruptShouldThrow);
 }
 
@@ -1792,11 +1822,7 @@
     if (!IS_LOCK_FAT(&acqObj->lock)) {
         LOGVV("fattening lockee %p (recur=%d)\n",
             acqObj, LW_LOCK_COUNT(acqObj->lock.thin));
-        Monitor* newMon = dvmCreateMonitor(acqObj);
-        lockMonitor(self, newMon);      // can't stall, don't need VMWAIT
-        newMon->lockCount += LW_LOCK_COUNT(acqObj->lock);
-        u4 hashState = LW_HASH_STATE(acqObj->lock) << LW_HASH_STATE_SHIFT;
-        acqObj->lock = (u4)newMon | hashState | LW_SHAPE_FAT;
+        inflateMonitor(self, acqObj);
     }
 
     /* if we don't have a stack trace for this monitor, establish one */
@@ -1840,11 +1866,7 @@
     if (!IS_LOCK_FAT(&mrl->obj->lock)) {
         LOGVV("fattening parent %p f/b/o child %p (recur=%d)\n",
             mrl->obj, acqObj, LW_LOCK_COUNT(mrl->obj->lock));
-        Monitor* newMon = dvmCreateMonitor(mrl->obj);
-        lockMonitor(self, newMon);      // can't stall, don't need VMWAIT
-        newMon->lockCount += LW_LOCK_COUNT(mrl->obj->lock);
-        u4 hashState = LW_HASH_STATE(mrl->obj->lock) << LW_HASH_STATE_SHIFT;
-        mrl->obj->lock = (u4)newMon | hashState | LW_SHAPE_FAT;
+        inflateMonitor(self, mrl->obj);
     }
 
     /*
diff --git a/vm/Sync.h b/vm/Sync.h
index b273538..1a168b9 100644
--- a/vm/Sync.h
+++ b/vm/Sync.h
@@ -141,6 +141,14 @@
 struct 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.
+ */
+struct Thread* dvmGetObjectLockHolder(struct Object* obj);
+
+/*
  * Checks whether the object is held by the specified thread.
  */
 bool dvmHoldsLock(struct Thread* thread, struct Object* obj);
diff --git a/vm/Thread.c b/vm/Thread.c
index b2d5776..4343694 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -30,8 +30,6 @@
 #include <errno.h>
 #include <fcntl.h>
 
-#include <cutils/sched_policy.h>
-
 #if defined(HAVE_PRCTL)
 #include <sys/prctl.h>
 #endif
@@ -2490,9 +2488,6 @@
     //abort();
 }
 
-/* "change flags" values for next two functions */
-enum { kChangedPriority = 0x01, kChangedPolicy = 0x02 };
-
 /*
  * If the thread is running at below-normal priority, temporarily elevate
  * it to "normal".
@@ -2501,7 +2496,7 @@
  * indicating what was changed, storing the previous values in the
  * provided locations.
  */
-static int raiseThreadPriorityIfNeeded(Thread* thread, int* pSavedThreadPrio,
+int dvmRaiseThreadPriorityIfNeeded(Thread* thread, int* pSavedThreadPrio,
     SchedPolicy* pSavedThreadPolicy)
 {
     errno = 0;
@@ -2554,7 +2549,7 @@
 /*
  * Reset the priority values for the thread in question.
  */
-static void resetThreadPriority(Thread* thread, int changeFlags,
+void dvmResetThreadPriority(Thread* thread, int changeFlags,
     int savedThreadPrio, SchedPolicy savedThreadPolicy)
 {
     if ((changeFlags & kChangedPolicy) != 0) {
@@ -2632,7 +2627,7 @@
              */
             if (retryCount == 2) {
                 assert(thread->systemTid != 0);
-                priChangeFlags = raiseThreadPriorityIfNeeded(thread,
+                priChangeFlags = dvmRaiseThreadPriorityIfNeeded(thread,
                     &savedThreadPrio, &savedThreadPolicy);
             }
         }
@@ -2687,7 +2682,7 @@
         //dvmDumpThread(thread, false);   /* suspended, so dump is safe */
     }
     if (priChangeFlags != 0) {
-        resetThreadPriority(thread, priChangeFlags, savedThreadPrio,
+        dvmResetThreadPriority(thread, priChangeFlags, savedThreadPrio,
             savedThreadPolicy);
     }
 }
@@ -3158,6 +3153,38 @@
     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;
+}
+
 
 /*
  * Conversion map for "nice" values.
diff --git a/vm/Thread.h b/vm/Thread.h
index ba9417a..e2af253 100644
--- a/vm/Thread.h
+++ b/vm/Thread.h
@@ -22,6 +22,9 @@
 
 #include "jni.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);
@@ -437,6 +440,22 @@
 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.
  */
@@ -469,6 +488,25 @@
  */
 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.
  */
diff --git a/vm/alloc/HeapWorker.c b/vm/alloc/HeapWorker.c
index 4c26a2f..fe37b2a 100644
--- a/vm/alloc/HeapWorker.c
+++ b/vm/alloc/HeapWorker.c
@@ -141,8 +141,32 @@
              * watchdog and just reset the timer.
              */
             LOGI("Debugger is attached -- suppressing HeapWorker watchdog\n");
-            heapWorkerInterpStartTime = now;        /* reset timer */
+            gDvm.gcHeap->heapWorkerInterpStartTime = now;   /* reset timer */
         } else if (delta > HEAP_WORKER_WATCHDOG_TIMEOUT) {
+            /*
+             * Before we give up entirely, see if maybe we're just not
+             * getting any CPU time because we're stuck in a background
+             * process group.  If we successfully move the thread into the
+             * foreground we'll just leave it there (it doesn't do anything
+             * if the process isn't GCing).
+             */
+            dvmLockThreadList(NULL);
+            Thread* thread = dvmGetThreadByHandle(gDvm.heapWorkerHandle);
+            dvmUnlockThreadList();
+
+            if (thread != NULL) {
+                int priChangeFlags, threadPrio;
+                SchedPolicy threadPolicy;
+                priChangeFlags = dvmRaiseThreadPriorityIfNeeded(thread,
+                        &threadPrio, &threadPolicy);
+                if (priChangeFlags != 0) {
+                    LOGI("HeapWorker watchdog expired, raising priority"
+                         " and retrying\n");
+                    gDvm.gcHeap->heapWorkerInterpStartTime = now;
+                    return;
+                }
+            }
+
             char* desc = dexProtoCopyMethodDescriptor(
                     &gDvm.gcHeap->heapWorkerCurrentMethod->prototype);
             LOGE("HeapWorker is wedged: %lldms spent inside %s.%s%s\n",
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index f2d934c..223448a 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -357,11 +357,11 @@
  */
 static void scanStaticFields(const ClassObject *clazz, GcMarkContext *ctx)
 {
-    StaticField *f;
+    const StaticField *f;
     int i;
 
     //TODO: Optimize this with a bit vector or something
-    f = clazz->sfields;
+    f = &clazz->sfields[0];
     for (i = 0; i < clazz->sfieldCount; i++) {
         char c = f->field.signature[0];
         if (c == '[' || c == 'L') {
@@ -469,7 +469,7 @@
     ClassObject *clazz;
 
     assert(dvmIsValidObject(obj));
-    LOGV_SCAN("0x%08x %s\n", (uint)obj, obj->clazz->name);
+    LOGV_SCAN("0x%08x %s\n", (uint)obj, obj->clazz->descriptor);
 
 #if WITH_HPROF
     if (gDvm.gcHeap->hprofContext != NULL) {
diff --git a/vm/compiler/Compiler.c b/vm/compiler/Compiler.c
index e9b30de..bd12e56 100644
--- a/vm/compiler/Compiler.c
+++ b/vm/compiler/Compiler.c
@@ -118,7 +118,13 @@
     int oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);
     dvmLockMutex(&gDvmJit.compilerLock);
     while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread) {
-        pthread_cond_wait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock);
+        /*
+         * 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);
     dvmChangeStatus(NULL, oldStatus);
@@ -156,6 +162,14 @@
            (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;
 
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index 434dbbf..8104ef2 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -241,6 +241,16 @@
 }
 #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)
@@ -500,6 +510,81 @@
     }
 }
 
+/*
+ * 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(ArrayObject, length);
+    int dataOffset = offsetof(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);
+    loadConstant(cUnit, r2, (int)dvmCanPutArrayElement);
+
+    /* Are we storing null?  If so, avoid check */
+    opRegImm(cUnit, kOpCmp, r0, 0);
+    ArmLIR *branchOver = opCondBranch(cUnit, kArmCondEq);
+
+    /* 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);
+    /* Bad? - roll back and re-execute if so */
+    genRegImmCheck(cUnit, kArmCondEq, r0, 0, mir->offset, pcrLabel);
+
+    /* Resume here - must reload element, regPtr & index preserved */
+    loadValueDirectFixed(cUnit, rlSrc, r0);
+
+    ArmLIR *target = newLIR0(cUnit, kArmPseudoTargetLabel);
+    target->defMask = ENCODE_ALL;
+    branchOver->generic.target = (LIR *) target;
+
+#if defined(WITH_SELF_VERIFICATION)
+    cUnit->heapMemOp = true;
+#endif
+    storeBaseIndexed(cUnit, regPtr, regIndex, r0,
+                     scale, kWord);
+#if defined(WITH_SELF_VERIFICATION)
+    cUnit->heapMemOp = false;
+#endif
+}
+
 static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir,
                            RegLocation rlDest, RegLocation rlSrc1,
                            RegLocation rlShift)
@@ -818,16 +903,6 @@
     return true;
 }
 
-/* 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 unconditional branch instructions */
 static ArmLIR *genUnconditionalBranch(CompilationUnit *cUnit, ArmLIR *target)
 {
@@ -1226,6 +1301,10 @@
     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);
 
@@ -2341,9 +2420,11 @@
             genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
             break;
         case OP_APUT:
-        case OP_APUT_OBJECT:
             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);
diff --git a/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c b/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c
new file mode 100644
index 0000000..fe2b1d4
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv7-a-neon/ArchVariant.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * 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;
+}
+
+/* Architecture-specific initializations and checks go here */
+bool dvmCompilerArchVariantInit(void)
+{
+    /* First, declare dvmCompiler_TEMPLATE_XXX for each template */
+#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
+#include "../../../template/armv5te-vfp/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+    int i = 0;
+    extern void dvmCompilerTemplateStart(void);
+
+    /*
+     * Then, populate the templateEntryOffsets array with the offsets from the
+     * the dvmCompilerTemplateStart symbol for each template.
+     */
+#define JIT_TEMPLATE(X) templateEntryOffsets[i++] = \
+    (intptr_t) dvmCompiler_TEMPLATE_##X - (intptr_t) dvmCompilerTemplateStart;
+#include "../../../template/armv5te-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;
+#endif
+
+    /* Codegen-specific assumptions */
+    assert(offsetof(ClassObject, vtable) < 128 &&
+           (offsetof(ClassObject, vtable) & 0x3) == 0);
+    assert(offsetof(ArrayObject, length) < 128 &&
+           (offsetof(ArrayObject, length) & 0x3) == 0);
+    assert(offsetof(ArrayObject, contents) < 256);
+
+    /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
+    assert(sizeof(StackSaveArea) < 236);
+
+    /*
+     * EA is calculated by doing "Rn + imm5 << 2", and there are 5 entry points
+     * that codegen may access, make sure that the offset from the top of the
+     * struct is less than 108.
+     */
+    assert(offsetof(InterpState, jitToInterpEntries) < 108);
+    return true;
+}
+
+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;
+}
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..9f862e8
--- /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.c b/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
new file mode 100644
index 0000000..baa9632
--- /dev/null
+++ b/vm/compiler/codegen/arm/armv7-a-neon/Codegen.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "libdex/OpCode.h"
+#include "dexdump/OpCodeNames.h"
+#include "compiler/CompilerInternals.h"
+#include "compiler/codegen/arm/ArmLIR.h"
+#include "mterp/common/FindInterface.h"
+#include "compiler/codegen/arm/Ralloc.h"
+#include "compiler/codegen/arm/Codegen.h"
+#include "compiler/Loop.h"
+#include "ArchVariant.h"
+
+/* Architectural independent building blocks */
+#include "../CodegenCommon.c"
+
+/* Thumb2-specific factory utilities */
+#include "../Thumb2/Factory.c"
+/* Factory utilities dependent on arch-specific features */
+#include "../CodegenFactory.c"
+
+/* Thumb2-specific codegen routines */
+#include "../Thumb2/Gen.c"
+/* Thumb2+VFP codegen routines */
+#include "../FP/Thumb2VFP.c"
+
+/* Thumb2-specific register allocation */
+#include "../Thumb2/Ralloc.c"
+
+/* MIR2LIR dispatcher and architectural independent codegen routines */
+#include "../CodegenDriver.c"
+
+/* Architecture manifest */
+#include "ArchVariant.c"
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..d991bed
--- /dev/null
+++ b/vm/compiler/template/armv7-a-neon/TemplateOpList.h
@@ -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.
+ */
+
+/*
+ * 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)
diff --git a/vm/compiler/template/config-armv7-a-neon b/vm/compiler/template/config-armv7-a-neon
new file mode 100644
index 0000000..be7af31
--- /dev/null
+++ b/vm/compiler/template/config-armv7-a-neon
@@ -0,0 +1,61 @@
+
+# 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-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/out/CompilerTemplateAsm-armv7-a-neon.S b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
new file mode 100644
index 0000000..51a5004
--- /dev/null
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv7-a-neon.S
@@ -0,0 +1,1538 @@
+/*
+ * 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  rGLUE     MterpGlue pointer
+
+The following registers have fixed assignments in mterp but are scratch
+registers in compiled code
+
+  reg nick      purpose
+  r4  rPC       interpreted program counter, used for fetching instructions
+  r7  rINST     first 16-bit code unit of current instruction
+  r8  rIBASE    interpreted instruction base pointer, used for computed goto
+
+Macros are provided for common operations.  Each macro MUST emit only
+one instruction to make instruction-counting easier.  They MUST NOT alter
+unspecified registers or condition codes.
+*/
+
+/* single-purpose registers, given names for clarity */
+#define rPC     r4
+#define rFP     r5
+#define rGLUE   r6
+#define rINST   r7
+#define rIBASE  r8
+
+/*
+ * Given a frame pointer, find the stack save area.
+ *
+ * In C this is "((StackSaveArea*)(_fp) -1)".
+ */
+#define SAVEAREA_FROM_FP(_reg, _fpreg) \
+    sub     _reg, _fpreg, #sizeofStackSaveArea
+
+#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
+ * ===========================================================================
+ */
+
+/*
+ * Macro for "MOV LR,PC / LDR PC,xxx", which is not allowed pre-ARMv5.
+ * Jump to subroutine.
+ *
+ * May modify IP and LR.
+ */
+.macro  LDR_PC_LR source
+    mov     lr, pc
+    ldr     pc, \source
+.endm
+
+
+    .global dvmCompilerTemplateStart
+    .type   dvmCompilerTemplateStart, %function
+    .text
+
+dvmCompilerTemplateStart:
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_CMP_LONG
+dvmCompiler_TEMPLATE_CMP_LONG:
+/* File: armv5te/TEMPLATE_CMP_LONG.S */
+    /*
+     * Compare two 64-bit values.  Puts 0, 1, or -1 into the destination
+     * register based on the results of the comparison.
+     *
+     * We load the full values with LDM, but in practice many values could
+     * be resolved by only looking at the high word.  This could be made
+     * faster or slower by splitting the LDM into a pair of LDRs.
+     *
+     * If we just wanted to set condition flags, we could do this:
+     *  subs    ip, r0, r2
+     *  sbcs    ip, r1, r3
+     *  subeqs  ip, r0, r2
+     * Leaving { <0, 0, >0 } in ip.  However, we have to set it to a specific
+     * integer value, which we can do with 2 conditional mov/mvn instructions
+     * (set 1, set -1; if they're equal we already have 0 in ip), giving
+     * us a constant 5-cycle path plus a branch at the end to the
+     * instruction epilogue code.  The multi-compare approach below needs
+     * 2 or 3 cycles + branch if the high word doesn't match, 6 + branch
+     * in the worst case (the 64-bit values are equal).
+     */
+    /* cmp-long vAA, vBB, vCC */
+    cmp     r1, r3                      @ compare (vBB+1, vCC+1)
+    blt     .LTEMPLATE_CMP_LONG_less            @ signed compare on high part
+    bgt     .LTEMPLATE_CMP_LONG_greater
+    subs    r0, r0, r2                  @ r0<- r0 - r2
+    bxeq     lr
+    bhi     .LTEMPLATE_CMP_LONG_greater         @ unsigned compare on low part
+.LTEMPLATE_CMP_LONG_less:
+    mvn     r0, #0                      @ r0<- -1
+    bx      lr
+.LTEMPLATE_CMP_LONG_greater:
+    mov     r0, #1                      @ r0<- 1
+    bx      lr
+
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_RETURN
+dvmCompiler_TEMPLATE_RETURN:
+/* File: armv5te/TEMPLATE_RETURN.S */
+    /*
+     * Unwind a frame from the Dalvik stack for compiled OP_RETURN_XXX.
+     * If the stored value in returnAddr
+     * is non-zero, the caller is compiled by the JIT thus return to the
+     * address in the code cache following the invoke instruction. Otherwise
+     * return to the special dvmJitToInterpNoChain entry point.
+     */
+    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
+    ldr     r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
+    ldr     r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
+    ldr     rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
+#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
+    ldr     r3, [rGLUE, #offGlue_self]  @ r3<- glue->self
+    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, .LdvmJitToInterpNoChain @ defined in footer.S
+    mov     rFP, r10                    @ publish new FP
+    ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+    ldr     r8, [r8]                    @ r8<- suspendCount
+
+    str     r2, [rGLUE, #offGlue_method]@ glue->method = newSave->method
+    ldr     r0, [r10, #offClassObject_pDvmDex] @ r0<- method->clazz->pDvmDex
+    str     rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
+    add     rPC, rPC, #6                @ publish new rPC (advance 6 bytes)
+    str     r0, [rGLUE, #offGlue_methodClassDex]
+    cmp     r8, #0                      @ check the suspendCount
+    movne   r9, #0                      @ clear the chaining cell address
+    str     r9, [r3, #offThread_inJitCodeCache] @ in code cache or not
+    cmp     r9, #0                      @ chaining cell exists?
+    blxne   r9                          @ jump to the chaining cell
+#if defined(JIT_STATS)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1                      @ callsite is interpreted
+1:
+    stmia   rGLUE, {rPC, rFP}           @ SAVE_PC_FP_TO_GLUE()
+    ldr     r2, .LdvmMterpStdBail       @ defined in footer.S
+    mov     r1, #0                      @ changeInterp = false
+    mov     r0, rGLUE                   @ Expecting rGLUE in r0
+    blx     r2                          @ exit the interpreter
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S */
+    /*
+     * For polymorphic callsites - setup the Dalvik frame and load Dalvik PC
+     * into rPC then jump to dvmJitToInterpNoChain to dispatch the
+     * runtime-resolved callee.
+     */
+    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+    ldrh    r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
+    ldrh    r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
+    ldr     r9, [rGLUE, #offGlue_interpStackEnd]    @ r9<- interpStackEnd
+    ldr     r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
+    add     r3, r1, #1  @ Thumb addr is odd
+    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
+    sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
+    sub     r10, r10, r2, lsl #2        @ r10<- bottom (newsave - outsSize)
+    ldr     r8, [r8]                    @ r8<- suspendCount (int)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlt    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    ldr     r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+    ldr     rPC, [r0, #offMethod_insns]     @ rPC<- methodToCall->insns
+
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ suspendCount != 0
+    bxne    lr                          @ bail to the interpreter
+    tst     r10, #ACC_NATIVE
+#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
+    ldr     r2, [rGLUE, #offGlue_self]      @ r2<- glue->self
+
+    @ Update "glue" values for the new method
+    str     r0, [rGLUE, #offGlue_method]    @ glue->method = methodToCall
+    str     r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [r2, #offThread_curFrame]  @ self->curFrame = newFp
+
+    @ Start executing the callee
+#if defined(JIT_STATS)
+    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, rPC = dalvikCallsite
+    @ methodToCall is guaranteed to be non-native
+.LinvokeChain:
+    ldrh    r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
+    ldrh    r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
+    ldr     r9, [rGLUE, #offGlue_interpStackEnd]    @ r9<- interpStackEnd
+    ldr     r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
+    add     r3, r1, #1  @ Thumb addr is odd
+    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
+    sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
+    add     r12, lr, #2                 @ setup the punt-to-interp address
+    sub     r10, r10, r2, lsl #2        @ r10<- bottom (newsave - outsSize)
+    ldr     r8, [r8]                    @ r8<- suspendCount (int)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlt    r12                         @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
+    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+    ldr     rPC, [r0, #offMethod_insns]     @ rPC<- methodToCall->insns
+
+
+    @ set up newSaveArea
+    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ suspendCount != 0
+    bxne    r12                         @ bail to the interpreter
+
+    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+    ldr     r2, [rGLUE, #offGlue_self]      @ r2<- glue->self
+
+    @ Update "glue" values for the new method
+    str     r0, [rGLUE, #offGlue_method]    @ glue->method = methodToCall
+    str     r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+    mov     rFP, r1                         @ fp = newFp
+    str     rFP, [r2, #offThread_curFrame]  @ self->curFrame = newFp
+
+    bx      lr                              @ return to the callee-chaining cell
+
+
+
+/* ------------------------------ */
+    .balign 4
+    .global dvmCompiler_TEMPLATE_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, [r2, #12]   @ r9 <- predictedChainCell->counter
+    cmp     r3, r8          @ predicted class == actual class?
+    beq     .LinvokeChain   @ predicted chain is valid
+    ldr     r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
+    sub     r1, r9, #1      @ count--
+    str     r1, [r2, #12]   @ write back to PredictedChainingCell->counter
+    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
+    ldrh    r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
+    ldr     r9, [rGLUE, #offGlue_interpStackEnd]    @ r9<- interpStackEnd
+    ldr     r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
+    add     r3, r1, #1  @ Thumb addr is odd
+    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
+    sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
+    ldr     r8, [r8]                    @ r3<- suspendCount (int)
+    cmp     r10, r9                     @ bottom < interpStackEnd?
+    bxlt    lr                          @ return to raise stack overflow excep.
+    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
+    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)]
+    ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
+    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+    cmp     r8, #0                      @ suspendCount != 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, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
+    mov     r2, #0
+    str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
+    str     r2, [r3, #offThread_inJitCodeCache] @ not in the jit code cache
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    mov     r9, r3                      @ r9<- glue->self (preserve)
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                      @ r2<- methodToCall
+    mov     r0, r1                      @ r0<- newFP
+    add     r1, rGLUE, #offGlue_retval  @ r1<- &retval
+
+    blx     r8                          @ off to the native code
+
+    @ native return; r9=self, r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [r9, #offThread_exception] @ check for exception
+    str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [r9, #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(JIT_STATS)
+    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
+    mov     r0, lr                      @ arg0 <- link register
+    mov     r1, sp                      @ arg1 <- stack pointer
+    ldr     r2, .LdvmSelfVerificationMemOpDecode @ defined in footer.S
+    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 + 1.
+     * On entry:
+     *    lr - if NULL:
+     *        r1 - the Dalvik PC to begin interpretation.
+     *    else
+     *        [lr, #-1] contains Dalvik PC to begin interpretation
+     *    rGLUE - pointer to interpState
+     *    rFP - Dalvik frame pointer
+     */
+    cmp     lr, #0
+    ldrne   r1,[lr, #-1]
+    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)
+    @ refresh Jit's on/off status
+    ldr     r0, [rGLUE, #offGlue_ppJitProfTable]
+    ldr     r0, [r0]
+    ldr     r2, .LdvmJitToInterpNoChain
+    str     r0, [rGLUE, #offGlue_pJitProfTable]
+    @ Bail to interpreter - no chain [note - r4 still contains rPC]
+#if defined(JIT_STATS)
+    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)
+    @ refresh Jit's on/off status & test for exception
+    ldr     r0, [rGLUE, #offGlue_ppJitProfTable]
+    ldr     r1, [rGLUE, #offGlue_self]
+    ldr     r0, [r0]
+    ldr     r1, [r1, #offThread_exception]
+    str     r0, [rGLUE, #offGlue_pJitProfTable]
+    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(JIT_STATS)
+    mov     r0, #kHeavyweightMonitor
+#endif
+    ldr     pc, .LdvmJitToInterpNoChain
+
+    .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
+/* File: armv5te/footer.S */
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+    .text
+    .align  2
+.LinvokeNative:
+    @ Prep for the native call
+    @ r1 = newFP, r0 = methodToCall
+    ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
+    mov     r2, #0
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
+    str     r2, [r3, #offThread_inJitCodeCache] @ not in jit code cache
+    str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
+    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
+                                        @ newFp->localRefCookie=top
+    mov     r9, r3                      @ r9<- glue->self (preserve)
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
+
+    mov     r2, r0                      @ r2<- methodToCall
+    mov     r0, r1                      @ r0<- newFP
+    add     r1, rGLUE, #offGlue_retval  @ r1<- &retval
+
+    LDR_PC_LR "[r2, #offMethod_nativeFunc]"
+
+    @ Refresh Jit's on/off status
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable]
+
+    @ native return; r9=self, r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
+    ldr     r1, [r9, #offThread_exception] @ check for exception
+    ldr     r3, [r3]    @ r1 <- pointer to Jit profile table
+    str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+    ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
+    str     r3, [rGLUE, #offGlue_pJitProfTable]  @ cache current JitProfTable
+
+    @ r0 = dalvikCallsitePC
+    bne     .LhandleException           @ no, handle exception
+
+    str     r2, [r9, #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(JIT_STATS)
+    mov     r0, #kCallsiteInterpreted
+#endif
+    mov     pc, r1
+
+/*
+ * On entry:
+ * r0  Faulting Dalvik PC
+ */
+.LhandleException:
+    ldr     r3, [rGLUE, #offGlue_self]  @ r3<- glue->self
+    mov     r2, #0
+    str     r2, [r3, #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
+.LdvmJitToInterpTraceSelectNoChain:
+    .word   dvmJitToInterpTraceSelectNoChain
+.LdvmJitToInterpNoChain:
+    .word   dvmJitToInterpNoChain
+.LdvmMterpStdBail:
+    .word   dvmMterpStdBail
+.LdvmMterpCommonExceptionThrown:
+    .word   dvmMterpCommonExceptionThrown
+.LdvmLockObject:
+    .word   dvmLockObject
+#if defined(WITH_SELF_VERIFICATION)
+.LdvmSelfVerificationMemOpDecode:
+    .word   dvmSelfVerificationMemOpDecode
+#endif
+.L__aeabi_cdcmple:
+    .word   __aeabi_cdcmple
+.L__aeabi_cfcmple:
+    .word   __aeabi_cfcmple
+
+    .global dmvCompilerTemplateEnd
+dmvCompilerTemplateEnd:
+
+#endif /* WITH_JIT */
+
diff --git a/vm/compiler/template/rebuild.sh b/vm/compiler/template/rebuild.sh
index 8a3861e..78ff84f 100755
--- a/vm/compiler/template/rebuild.sh
+++ b/vm/compiler/template/rebuild.sh
@@ -19,5 +19,5 @@
 # generated as part of the build.
 #
 set -e
-for arch in armv5te armv5te-vfp armv7-a; do TARGET_ARCH_EXT=$arch make -f Makefile-template; done
+for arch in armv5te armv5te-vfp armv7-a armv7-a-neon; do TARGET_ARCH_EXT=$arch make -f Makefile-template; done
 
diff --git a/vm/hprof/HprofHeap.c b/vm/hprof/HprofHeap.c
index 31063e4..5a35e77 100644
--- a/vm/hprof/HprofHeap.c
+++ b/vm/hprof/HprofHeap.c
@@ -30,6 +30,15 @@
 #define OBJECTS_PER_SEGMENT     ((size_t)128)
 #define BYTES_PER_SEGMENT       ((size_t)4096)
 
+/* The static field-name for the synthetic object generated to account
+ * for class Static overhead.
+ */
+#define STATIC_OVERHEAD_NAME    "$staticOverhead"
+/* The ID for the synthetic object generated to account for class
+ * Static overhead.
+ */
+#define CLASS_STATICS_ID(clazz) ((hprof_object_id)(((u4)(clazz)) | 1))
+
 int
 hprofStartHeapDump(hprof_context_t *ctx)
 {
@@ -267,16 +276,11 @@
     clazz = obj->clazz;
 
     if (clazz == NULL) {
-        /* This object was probably just allocated and hasn't been
-         * initialized yet.  Add an instance entry to make a note of
-         * it;  there's not much else that we can do.
+        /* This object will bother HprofReader, because it has a NULL
+         * class, so just don't dump it. It could be
+         * gDvm.unlinkedJavaLangClass or it could be an object just
+         * allocated which hasn't been initialized yet.
          */
-        hprofAddU1ToRecord(rec, HPROF_INSTANCE_DUMP);
-
-        hprofAddIdToRecord(rec, (hprof_object_id)obj);
-        hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
-        hprofAddIdToRecord(rec, (hprof_class_object_id)clazz);  // NULL
-        hprofAddIdToRecord(rec, 0);    // no instance data
     } else if (clazz == gDvm.unlinkedJavaLangClass) {
         /* obj is a ClassObject that hasn't been linked yet.
          */
@@ -302,11 +306,26 @@
 
         if (clazz == gDvm.classJavaLangClass) {
             const ClassObject *thisClass = (const ClassObject *)obj;
-            int i, n;
+            int i, sFieldCount, iFieldCount;
             /* obj is a ClassObject.
              */
-            hprofAddU1ToRecord(rec, HPROF_CLASS_DUMP);
+            sFieldCount = thisClass->sfieldCount;
+            if (sFieldCount != 0) {
+                int byteLength = sFieldCount*sizeof(StaticField);
+                /* Create a byte array to reflect the allocation of the
+                 * StaticField array at the end of this class.
+                 */
+                hprofAddU1ToRecord(rec, HPROF_PRIMITIVE_ARRAY_DUMP);
+                hprofAddIdToRecord(rec, CLASS_STATICS_ID(obj));
+                hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
+                hprofAddU4ToRecord(rec, byteLength);
+                hprofAddU1ToRecord(rec, hprof_basic_byte);
+                for (i = 0; i < byteLength; i++) {
+                    hprofAddU1ToRecord(rec, 0);
+                }
+            }
 
+            hprofAddU1ToRecord(rec, HPROF_CLASS_DUMP);
             hprofAddIdToRecord(rec, hprofLookupClassId(thisClass));
             hprofAddU4ToRecord(rec, stackTraceSerialNumber(thisClass));
             hprofAddIdToRecord(rec, hprofLookupClassId(thisClass->super));
@@ -316,6 +335,9 @@
             hprofAddIdToRecord(rec, (hprof_id)0);           // reserved
             hprofAddIdToRecord(rec, (hprof_id)0);           // reserved
             if (obj == (Object *)gDvm.classJavaLangClass) {
+                // ClassObjects have their static fields appended, so
+                // aren't all the same size. But they're at least this
+                // size.
                 hprofAddU4ToRecord(rec, sizeof(ClassObject)); // instance size
             } else {
                 hprofAddU4ToRecord(rec, thisClass->objectSize); // instance size
@@ -325,34 +347,41 @@
 
             /* Static fields
              */
-            n = thisClass->sfieldCount;
-            hprofAddU2ToRecord(rec, (u2)n);
-            for (i = 0; i < n; i++) {
-                const StaticField *f = &thisClass->sfields[i];
-                hprof_basic_type t;
-                size_t size;
+            if (sFieldCount == 0) {
+                hprofAddU2ToRecord(rec, (u2)0);
+            } else {
+                hprofAddU2ToRecord(rec, (u2)(sFieldCount+1));
+                hprofAddIdToRecord(rec,
+                                   hprofLookupStringId(STATIC_OVERHEAD_NAME));
+                hprofAddU1ToRecord(rec, hprof_basic_object);
+                hprofAddIdToRecord(rec, CLASS_STATICS_ID(obj));
+                for (i = 0; i < sFieldCount; i++) {
+                    hprof_basic_type t;
+                    size_t size;
+                    const StaticField *f = &thisClass->sfields[i];
 
-                t = signatureToBasicTypeAndSize(f->field.signature, &size);
-                hprofAddIdToRecord(rec, hprofLookupStringId(f->field.name));
-                hprofAddU1ToRecord(rec, t);
-                if (size == 1) {
-                    hprofAddU1ToRecord(rec, (u1)f->value.b);
-                } else if (size == 2) {
-                    hprofAddU2ToRecord(rec, (u2)f->value.c);
-                } else if (size == 4) {
-                    hprofAddU4ToRecord(rec, (u4)f->value.i);
-                } else if (size == 8) {
-                    hprofAddU8ToRecord(rec, (u8)f->value.j);
-                } else {
-                    assert(false);
+                    t = signatureToBasicTypeAndSize(f->field.signature, &size);
+                    hprofAddIdToRecord(rec, hprofLookupStringId(f->field.name));
+                    hprofAddU1ToRecord(rec, t);
+                    if (size == 1) {
+                        hprofAddU1ToRecord(rec, (u1)f->value.b);
+                    } else if (size == 2) {
+                        hprofAddU2ToRecord(rec, (u2)f->value.c);
+                    } else if (size == 4) {
+                        hprofAddU4ToRecord(rec, (u4)f->value.i);
+                    } else if (size == 8) {
+                        hprofAddU8ToRecord(rec, (u8)f->value.j);
+                    } else {
+                        assert(false);
+                    }
                 }
             }
 
             /* Instance fields for this class (no superclass fields)
              */
-            n = thisClass->ifieldCount;
-            hprofAddU2ToRecord(rec, (u2)n);
-            for (i = 0; i < n; i++) {
+            iFieldCount = thisClass->ifieldCount;
+            hprofAddU2ToRecord(rec, (u2)iFieldCount);
+            for (i = 0; i < iFieldCount; i++) {
                 const InstField *f = &thisClass->ifields[i];
                 hprof_basic_type t;
 
diff --git a/vm/interp/InterpDefs.h b/vm/interp/InterpDefs.h
index 31856df..2bc9c7d 100644
--- a/vm/interp/InterpDefs.h
+++ b/vm/interp/InterpDefs.h
@@ -246,7 +246,7 @@
  */
 static inline bool dvmJitDebuggerOrProfilerActive()
 {
-    return gDvmJit.pJitEntryTable != NULL
+    return gDvmJit.pProfTable != NULL
 #if defined(WITH_PROFILER)
         || gDvm.activeProfilers != 0
 #endif
diff --git a/vm/interp/Jit.c b/vm/interp/Jit.c
index 185182f..1d7961e 100644
--- a/vm/interp/Jit.c
+++ b/vm/interp/Jit.c
@@ -409,23 +409,21 @@
             if (gDvmJit.pJitEntryTable[i].u.info.chain != gDvmJit.jitTableSize)
                 chains++;
         }
-        LOGD("size if %d, entries used is %d",
+        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");
+        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(JIT_STATS)
-        LOGD(
-         "JIT: Lookups: %d hits, %d misses; %d normal, %d punt",
-         gDvmJit.addrLookupsFound, gDvmJit.addrLookupsNotFound,
-         gDvmJit.normalExit, gDvmJit.puntExit);
-        LOGD(
-         "JIT: noChainExit: %d IC miss, %d interp callsite, %d switch overflow",
-         gDvmJit.noChainExit[kInlineCacheMiss],
-         gDvmJit.noChainExit[kCallsiteInterpreted],
-         gDvmJit.noChainExit[kSwitchOverflow]);
+        LOGD("JIT: Lookups: %d hits, %d misses; %d normal, %d punt",
+             gDvmJit.addrLookupsFound, gDvmJit.addrLookupsNotFound,
+             gDvmJit.normalExit, gDvmJit.puntExit);
+        LOGD("JIT: noChainExit: %d IC miss, %d interp callsite, "
+             "%d switch overflow",
+             gDvmJit.noChainExit[kInlineCacheMiss],
+             gDvmJit.noChainExit[kCallsiteInterpreted],
+             gDvmJit.noChainExit[kSwitchOverflow]);
 
         LOGD("JIT: Invoke: %d mono, %d poly, %d native, %d return",
              gDvmJit.invokeMonomorphic, gDvmJit.invokePolymorphic,
diff --git a/vm/interp/Stack.c b/vm/interp/Stack.c
index 8d8cc1b..1ebbcf0 100644
--- a/vm/interp/Stack.c
+++ b/vm/interp/Stack.c
@@ -1093,6 +1093,85 @@
 
 
 /*
+ * 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.
+ *
+ * We assume the thread list lock is currently 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->curFrame;
+
+    if (framePtr == NULL || dvmIsBreakFrame(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\n", 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)\n",
+            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)\n",
+            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)\n",
+            reg, method->registersSize);
+        return false;
+    }
+
+    /* get and check the object in that register */
+    u4* fp = (u4*) framePtr;
+    Object* obj = (Object*) fp[reg];
+    if (!dvmIsValidObject(obj)) {
+        LOGD("ExtrMon: invalid object %p at %p[%d]\n", 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;
+}
+
+/*
  * Dump stack frames, starting from the specified frame and moving down.
  *
  * Each frame holds a pointer to the currently executing method, and the
@@ -1151,21 +1230,44 @@
             }
             free(className);
 
-            if (first &&
-                (thread->status == THREAD_WAIT ||
-                 thread->status == THREAD_TIMED_WAIT))
-            {
-                /* warning: wait status not stable, even in suspend */
-                Monitor* mon = thread->waitMonitor;
-                Object* obj = dvmGetMonitorObject(mon);
-                if (obj != NULL) {
-                    className = dvmDescriptorToDot(obj->clazz->descriptor);
-                    dvmPrintDebugMessage(target,
-                        "  - waiting on <%p> (a %s)\n", mon, className);
-                    free(className);
+            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) {
+                        className = dvmDescriptorToDot(obj->clazz->descriptor);
+                        dvmPrintDebugMessage(target,
+                            "  - waiting on <%p> (a %s)\n", obj, className);
+                        free(className);
+                    }
+                } else if (thread->status == THREAD_MONITOR) {
+                    Object* obj;
+                    Thread* owner;
+                    if (extractMonitorEnterObject(thread, &obj, &owner)) {
+                        className = dvmDescriptorToDot(obj->clazz->descriptor);
+                        if (owner != NULL) {
+                            char* threadName = dvmGetThreadName(owner);
+                            dvmPrintDebugMessage(target,
+                                "  - waiting to lock <%p> (a %s) held by threadid=%d (%s)\n",
+                                obj, className, owner->threadId, threadName);
+                            free(threadName);
+                        } else {
+                            dvmPrintDebugMessage(target,
+                                "  - waiting to lock <%p> (a %s) held by ???\n",
+                                obj, className);
+                        }
+                        free(className);
+                    }
                 }
             }
-
         }
 
         /*
diff --git a/vm/mterp/armv5te/entry.S b/vm/mterp/armv5te/entry.S
index 174a37a..9b2a88d 100644
--- a/vm/mterp/armv5te/entry.S
+++ b/vm/mterp/armv5te/entry.S
@@ -60,7 +60,7 @@
 
     /* set up "named" registers, figure out entry point */
     mov     rGLUE, r0                   @ set rGLUE
-    ldrb    r1, [r0, #offGlue_entryPoint]   @ InterpEntry enum is char
+    ldr     r1, [r0, #offGlue_entryPoint]   @ enum is 4 bytes in aapcs-EABI
     LOAD_PC_FP_FROM_GLUE()              @ load rPC and rFP from "glue"
     adr     rIBASE, dvmAsmInstructionStart  @ set rIBASE
     cmp     r1, #kInterpEntryInstr      @ usual case?
@@ -102,7 +102,7 @@
     cmp     rPC,r2
     bne     .Lno_singleStep             @ must have branched, don't resume
     mov     r1, #kInterpEntryInstr
-    strb    r1, [rGLUE, #offGlue_entryPoint]
+    str     r1, [rGLUE, #offGlue_entryPoint]
     ldr     rINST, .LdvmCompilerTemplate
     bx      r0                          @ re-enter the translation
 .LdvmCompilerTemplate:
diff --git a/vm/mterp/armv5te/footer.S b/vm/mterp/armv5te/footer.S
index e5468ae..3452263 100644
--- a/vm/mterp/armv5te/footer.S
+++ b/vm/mterp/armv5te/footer.S
@@ -755,11 +755,6 @@
     mov     r9, #0
     bl      common_periodicChecks
 
-#if defined(WITH_JIT)
-    mov     r2,#kJitTSelectAbort        @ abandon trace selection in progress
-    str     r2,[rGLUE,#offGlue_jitState]
-#endif
-
     ldr     r10, [rGLUE, #offGlue_self] @ r10<- glue->self
     ldr     r9, [r10, #offThread_exception] @ r9<- self->exception
     mov     r1, r10                     @ r1<- self
diff --git a/vm/mterp/config-armv7-a-neon b/vm/mterp/config-armv7-a-neon
new file mode 100644
index 0000000..9193632
--- /dev/null
+++ b/vm/mterp/config-armv7-a-neon
@@ -0,0 +1,167 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Configuration for ARMv7-A targets.
+#
+# This target includes Thumb-2 and Thumb2-EE support, as well as VFPLite.
+#
+# The difference in performance between this and ARMv5TE appears to be
+# negligible on a Cortex-A8 CPU, so this is really just an experiment.
+#
+
+handler-size 64
+
+# source for the instruction table stub
+asm-stub armv5te/stub.S
+
+# file header and basic definitions
+import c/header.c
+import armv5te/header.S
+
+# C pre-processor defines for stub C instructions
+import cstubs/stubdefs.c
+
+# highly-platform-specific defs
+import armv5te/platform.S
+
+# common defs for the C helpers; include this before the instruction handlers
+import c/opcommon.c
+
+# arch-specific entry point to interpreter
+import armv5te/entry.S
+
+# opcode list; argument to op-start is default directory
+op-start armv5te
+    # handlers that take advantage of >= ARMv6T2 instructions
+    op OP_ADD_DOUBLE_2ADDR armv6t2
+    op OP_ADD_FLOAT_2ADDR armv6t2
+    op OP_ADD_INT_2ADDR armv6t2
+    op OP_ADD_INT_LIT16 armv6t2
+    op OP_ADD_LONG_2ADDR armv6t2
+    op OP_AND_INT_2ADDR armv6t2
+    op OP_AND_INT_LIT16 armv6t2
+    op OP_AND_LONG_2ADDR armv6t2
+    op OP_ARRAY_LENGTH armv6t2
+    op OP_CONST_4 armv6t2
+    op OP_DIV_DOUBLE_2ADDR armv6t2
+    op OP_DIV_FLOAT_2ADDR armv6t2
+    op OP_DIV_INT_2ADDR armv6t2
+    op OP_DIV_INT_LIT16 armv6t2
+    op OP_DIV_LONG_2ADDR armv6t2
+    op OP_DOUBLE_TO_FLOAT armv6t2
+    op OP_DOUBLE_TO_INT armv6t2
+    op OP_DOUBLE_TO_LONG armv6t2
+    op OP_FLOAT_TO_DOUBLE armv6t2
+    op OP_FLOAT_TO_INT armv6t2
+    op OP_FLOAT_TO_LONG armv6t2
+    op OP_IF_EQ armv6t2
+    op OP_IF_GE armv6t2
+    op OP_IF_GT armv6t2
+    op OP_IF_LE armv6t2
+    op OP_IF_LT armv6t2
+    op OP_IF_NE armv6t2
+    op OP_IGET armv6t2
+    op OP_IGET_QUICK armv6t2
+    op OP_IGET_WIDE armv6t2
+    op OP_IGET_WIDE_QUICK armv6t2
+    op OP_INT_TO_BYTE armv6t2
+    op OP_INT_TO_CHAR armv6t2
+    op OP_INT_TO_DOUBLE armv6t2
+    op OP_INT_TO_FLOAT armv6t2
+    op OP_INT_TO_LONG armv6t2
+    op OP_INT_TO_SHORT armv6t2
+    op OP_IPUT armv6t2
+    op OP_IPUT_QUICK armv6t2
+    op OP_IPUT_WIDE armv6t2
+    op OP_IPUT_WIDE_QUICK armv6t2
+    op OP_LONG_TO_DOUBLE armv6t2
+    op OP_LONG_TO_FLOAT armv6t2
+    op OP_MOVE armv6t2
+    op OP_MOVE_WIDE armv6t2
+    op OP_MUL_DOUBLE_2ADDR armv6t2
+    op OP_MUL_FLOAT_2ADDR armv6t2
+    op OP_MUL_INT_2ADDR armv6t2
+    op OP_MUL_INT_LIT16 armv6t2
+    op OP_MUL_LONG_2ADDR armv6t2
+    op OP_NEG_DOUBLE armv6t2
+    op OP_NEG_FLOAT armv6t2
+    op OP_NEG_INT armv6t2
+    op OP_NEG_LONG armv6t2
+    op OP_NOT_INT armv6t2
+    op OP_NOT_LONG armv6t2
+    op OP_OR_INT_2ADDR armv6t2
+    op OP_OR_INT_LIT16 armv6t2
+    op OP_OR_LONG_2ADDR armv6t2
+    op OP_REM_DOUBLE_2ADDR armv6t2
+    op OP_REM_FLOAT_2ADDR armv6t2
+    op OP_REM_INT_2ADDR armv6t2
+    op OP_REM_INT_LIT16 armv6t2
+    op OP_REM_LONG_2ADDR armv6t2
+    op OP_RSUB_INT armv6t2
+    op OP_SHL_INT_2ADDR armv6t2
+    op OP_SHL_LONG_2ADDR armv6t2
+    op OP_SHR_INT_2ADDR armv6t2
+    op OP_SHR_LONG_2ADDR armv6t2
+    op OP_SUB_DOUBLE_2ADDR armv6t2
+    op OP_SUB_FLOAT_2ADDR armv6t2
+    op OP_SUB_INT_2ADDR armv6t2
+    op OP_SUB_LONG_2ADDR armv6t2
+    op OP_USHR_INT_2ADDR armv6t2
+    op OP_USHR_LONG_2ADDR armv6t2
+    op OP_XOR_INT_2ADDR armv6t2
+    op OP_XOR_INT_LIT16 armv6t2
+    op OP_XOR_LONG_2ADDR armv6t2
+
+    # floating point handlers that use VFP
+    # these override the handlers specified earlier
+    op OP_ADD_DOUBLE arm-vfp
+    op OP_ADD_DOUBLE_2ADDR arm-vfp
+    op OP_ADD_FLOAT arm-vfp
+    op OP_ADD_FLOAT_2ADDR arm-vfp
+    op OP_CMPG_DOUBLE arm-vfp
+    op OP_CMPG_FLOAT arm-vfp
+    op OP_CMPL_DOUBLE arm-vfp
+    op OP_CMPL_FLOAT arm-vfp
+    op OP_DIV_DOUBLE arm-vfp
+    op OP_DIV_DOUBLE_2ADDR arm-vfp
+    op OP_DIV_FLOAT arm-vfp
+    op OP_DIV_FLOAT_2ADDR arm-vfp
+    op OP_DOUBLE_TO_FLOAT arm-vfp
+    op OP_DOUBLE_TO_INT arm-vfp
+    op OP_FLOAT_TO_DOUBLE arm-vfp
+    op OP_FLOAT_TO_INT arm-vfp
+    op OP_INT_TO_DOUBLE arm-vfp
+    op OP_INT_TO_FLOAT arm-vfp
+    op OP_MUL_DOUBLE arm-vfp
+    op OP_MUL_DOUBLE_2ADDR arm-vfp
+    op OP_MUL_FLOAT arm-vfp
+    op OP_MUL_FLOAT_2ADDR arm-vfp
+    op OP_SUB_DOUBLE arm-vfp
+    op OP_SUB_DOUBLE_2ADDR arm-vfp
+    op OP_SUB_FLOAT arm-vfp
+    op OP_SUB_FLOAT_2ADDR arm-vfp
+op-end
+
+# "helper" code for C; include if you use any of the C stubs (this generates
+# object code, so it's normally excluded)
+##import c/gotoTargets.c
+
+# end of defs; include this when cstubs/stubdefs.c is included
+import cstubs/enddefs.c
+
+# common subroutines for asm
+import armv5te/footer.S
+import armv5te/debug.c
+
diff --git a/vm/mterp/out/InterpAsm-armv4t.S b/vm/mterp/out/InterpAsm-armv4t.S
index 7f70cbb..6068de5 100644
--- a/vm/mterp/out/InterpAsm-armv4t.S
+++ b/vm/mterp/out/InterpAsm-armv4t.S
@@ -306,7 +306,7 @@
 
     /* set up "named" registers, figure out entry point */
     mov     rGLUE, r0                   @ set rGLUE
-    ldrb    r1, [r0, #offGlue_entryPoint]   @ InterpEntry enum is char
+    ldr     r1, [r0, #offGlue_entryPoint]   @ enum is 4 bytes in aapcs-EABI
     LOAD_PC_FP_FROM_GLUE()              @ load rPC and rFP from "glue"
     adr     rIBASE, dvmAsmInstructionStart  @ set rIBASE
     cmp     r1, #kInterpEntryInstr      @ usual case?
@@ -348,7 +348,7 @@
     cmp     rPC,r2
     bne     .Lno_singleStep             @ must have branched, don't resume
     mov     r1, #kInterpEntryInstr
-    strb    r1, [rGLUE, #offGlue_entryPoint]
+    str     r1, [rGLUE, #offGlue_entryPoint]
     ldr     rINST, .LdvmCompilerTemplate
     bx      r0                          @ re-enter the translation
 .LdvmCompilerTemplate:
@@ -10426,11 +10426,6 @@
     mov     r9, #0
     bl      common_periodicChecks
 
-#if defined(WITH_JIT)
-    mov     r2,#kJitTSelectAbort        @ abandon trace selection in progress
-    str     r2,[rGLUE,#offGlue_jitState]
-#endif
-
     ldr     r10, [rGLUE, #offGlue_self] @ r10<- glue->self
     ldr     r9, [r10, #offThread_exception] @ r9<- self->exception
     mov     r1, r10                     @ r1<- self
diff --git a/vm/mterp/out/InterpAsm-armv5te-vfp.S b/vm/mterp/out/InterpAsm-armv5te-vfp.S
index 36f7803..6ab1a37 100644
--- a/vm/mterp/out/InterpAsm-armv5te-vfp.S
+++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S
@@ -306,7 +306,7 @@
 
     /* set up "named" registers, figure out entry point */
     mov     rGLUE, r0                   @ set rGLUE
-    ldrb    r1, [r0, #offGlue_entryPoint]   @ InterpEntry enum is char
+    ldr     r1, [r0, #offGlue_entryPoint]   @ enum is 4 bytes in aapcs-EABI
     LOAD_PC_FP_FROM_GLUE()              @ load rPC and rFP from "glue"
     adr     rIBASE, dvmAsmInstructionStart  @ set rIBASE
     cmp     r1, #kInterpEntryInstr      @ usual case?
@@ -348,7 +348,7 @@
     cmp     rPC,r2
     bne     .Lno_singleStep             @ must have branched, don't resume
     mov     r1, #kInterpEntryInstr
-    strb    r1, [rGLUE, #offGlue_entryPoint]
+    str     r1, [rGLUE, #offGlue_entryPoint]
     ldr     rINST, .LdvmCompilerTemplate
     bx      r0                          @ re-enter the translation
 .LdvmCompilerTemplate:
@@ -9944,11 +9944,6 @@
     mov     r9, #0
     bl      common_periodicChecks
 
-#if defined(WITH_JIT)
-    mov     r2,#kJitTSelectAbort        @ abandon trace selection in progress
-    str     r2,[rGLUE,#offGlue_jitState]
-#endif
-
     ldr     r10, [rGLUE, #offGlue_self] @ r10<- glue->self
     ldr     r9, [r10, #offThread_exception] @ r9<- self->exception
     mov     r1, r10                     @ r1<- self
diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S
index 2bfbb6a..6990b44 100644
--- a/vm/mterp/out/InterpAsm-armv5te.S
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -306,7 +306,7 @@
 
     /* set up "named" registers, figure out entry point */
     mov     rGLUE, r0                   @ set rGLUE
-    ldrb    r1, [r0, #offGlue_entryPoint]   @ InterpEntry enum is char
+    ldr     r1, [r0, #offGlue_entryPoint]   @ enum is 4 bytes in aapcs-EABI
     LOAD_PC_FP_FROM_GLUE()              @ load rPC and rFP from "glue"
     adr     rIBASE, dvmAsmInstructionStart  @ set rIBASE
     cmp     r1, #kInterpEntryInstr      @ usual case?
@@ -348,7 +348,7 @@
     cmp     rPC,r2
     bne     .Lno_singleStep             @ must have branched, don't resume
     mov     r1, #kInterpEntryInstr
-    strb    r1, [rGLUE, #offGlue_entryPoint]
+    str     r1, [rGLUE, #offGlue_entryPoint]
     ldr     rINST, .LdvmCompilerTemplate
     bx      r0                          @ re-enter the translation
 .LdvmCompilerTemplate:
@@ -10420,11 +10420,6 @@
     mov     r9, #0
     bl      common_periodicChecks
 
-#if defined(WITH_JIT)
-    mov     r2,#kJitTSelectAbort        @ abandon trace selection in progress
-    str     r2,[rGLUE,#offGlue_jitState]
-#endif
-
     ldr     r10, [rGLUE, #offGlue_self] @ r10<- glue->self
     ldr     r9, [r10, #offThread_exception] @ r9<- self->exception
     mov     r1, r10                     @ r1<- self
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..a60f78c
--- /dev/null
+++ b/vm/mterp/out/InterpAsm-armv7-a-neon.S
@@ -0,0 +1,10144 @@
+/*
+ * 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  rGLUE     MterpGlue pointer
+  r7  rINST     first 16-bit code unit of current instruction
+  r8  rIBASE    interpreted instruction base pointer, used for computed goto
+
+Macros are provided for common operations.  Each macro MUST emit only
+one instruction to make instruction-counting easier.  They MUST NOT alter
+unspecified registers or condition codes.
+*/
+
+/* single-purpose registers, given names for clarity */
+#define rPC     r4
+#define rFP     r5
+#define rGLUE   r6
+#define rINST   r7
+#define rIBASE  r8
+
+/* save/restore the PC and/or FP from the glue struct */
+#define LOAD_PC_FROM_GLUE()     ldr     rPC, [rGLUE, #offGlue_pc]
+#define SAVE_PC_TO_GLUE()       str     rPC, [rGLUE, #offGlue_pc]
+#define LOAD_FP_FROM_GLUE()     ldr     rFP, [rGLUE, #offGlue_fp]
+#define SAVE_FP_TO_GLUE()       str     rFP, [rGLUE, #offGlue_fp]
+#define LOAD_PC_FP_FROM_GLUE()  ldmia   rGLUE, {rPC, rFP}
+#define SAVE_PC_FP_TO_GLUE()    stmia   rGLUE, {rPC, rFP}
+
+/*
+ * "export" the PC to the stack frame, f/b/o future exception objects.  Must
+ * be done *before* something calls dvmThrowException.
+ *
+ * In C this is "SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc", i.e.
+ * fp - sizeof(StackSaveArea) + offsetof(SaveArea, xtra.currentPc)
+ *
+ * It's okay to do this more than once.
+ */
+#define EXPORT_PC() \
+    str     rPC, [rFP, #(-sizeofStackSaveArea + offStackSaveArea_currentPc)]
+
+/*
+ * Given a frame pointer, find the stack save area.
+ *
+ * In C this is "((StackSaveArea*)(_fp) -1)".
+ */
+#define SAVEAREA_FROM_FP(_reg, _fpreg) \
+    sub     _reg, _fpreg, #sizeofStackSaveArea
+
+/*
+ * Fetch the next instruction from rPC into rINST.  Does not advance rPC.
+ */
+#define FETCH_INST()            ldrh    rINST, [rPC]
+
+/*
+ * Fetch the next instruction from the specified offset.  Advances rPC
+ * to point to the next instruction.  "_count" is in 16-bit code units.
+ *
+ * Because of the limited size of immediate constants on ARM, this is only
+ * suitable for small forward movements (i.e. don't try to implement "goto"
+ * with this).
+ *
+ * This must come AFTER anything that can throw an exception, or the
+ * exception catch may miss.  (This also implies that it must come after
+ * EXPORT_PC().)
+ */
+#define FETCH_ADVANCE_INST(_count) ldrh    rINST, [rPC, #(_count*2)]!
+
+/*
+ * The operation performed here is similar to FETCH_ADVANCE_INST, except the
+ * src and dest registers are parameterized (not hard-wired to rPC and rINST).
+ */
+#define PREFETCH_ADVANCE_INST(_dreg, _sreg, _count) \
+        ldrh    _dreg, [_sreg, #(_count*2)]!
+
+/*
+ * Fetch the next instruction from an offset specified by _reg.  Updates
+ * rPC to point to the next instruction.  "_reg" must specify the distance
+ * in bytes, *not* 16-bit code units, and may be a signed value.
+ *
+ * We want to write "ldrh rINST, [rPC, _reg, lsl #2]!", but some of the
+ * bits that hold the shift distance are used for the half/byte/sign flags.
+ * In some cases we can pre-double _reg for free, so we require a byte offset
+ * here.
+ */
+#define FETCH_ADVANCE_INST_RB(_reg) ldrh    rINST, [rPC, _reg]!
+
+/*
+ * Fetch a half-word code unit from an offset past the current PC.  The
+ * "_count" value is in 16-bit code units.  Does not advance rPC.
+ *
+ * The "_S" variant works the same but treats the value as signed.
+ */
+#define FETCH(_reg, _count)     ldrh    _reg, [rPC, #(_count*2)]
+#define FETCH_S(_reg, _count)   ldrsh   _reg, [rPC, #(_count*2)]
+
+/*
+ * Fetch one byte from an offset past the current PC.  Pass in the same
+ * "_count" as you would for FETCH, and an additional 0/1 indicating which
+ * byte of the halfword you want (lo/hi).
+ */
+#define FETCH_B(_reg, _count, _byte) ldrb     _reg, [rPC, #(_count*2+_byte)]
+
+/*
+ * Put the instruction's opcode field into the specified register.
+ */
+#define GET_INST_OPCODE(_reg)   and     _reg, rINST, #255
+
+/*
+ * Put the prefetched instruction's opcode field into the specified register.
+ */
+#define GET_PREFETCHED_OPCODE(_oreg, _ireg)   and     _oreg, _ireg, #255
+
+/*
+ * Begin executing the opcode in _reg.  Because this only jumps within the
+ * interpreter, we don't have to worry about pre-ARMv5 THUMB interwork.
+ */
+#define GOTO_OPCODE(_reg)       add     pc, rIBASE, _reg, lsl #6
+#define GOTO_OPCODE_IFEQ(_reg)  addeq   pc, rIBASE, _reg, lsl #6
+#define GOTO_OPCODE_IFNE(_reg)  addne   pc, rIBASE, _reg, lsl #6
+
+/*
+ * Get/set the 32-bit value from a Dalvik register.
+ */
+#define GET_VREG(_reg, _vreg)   ldr     _reg, [rFP, _vreg, lsl #2]
+#define SET_VREG(_reg, _vreg)   str     _reg, [rFP, _vreg, lsl #2]
+
+#if defined(WITH_JIT)
+#define GET_JIT_PROF_TABLE(_reg)    ldr     _reg,[rGLUE,#offGlue_pJitProfTable]
+#define GET_JIT_THRESHOLD(_reg)     ldr     _reg,[rGLUE,#offGlue_jitThreshold]
+#endif
+
+/*
+ * Convert a virtual register index into an address.
+ */
+#define VREG_INDEX_TO_ADDR(_reg, _vreg) \
+        add     _reg, rFP, _vreg, lsl #2
+
+/*
+ * This is a #include, not a %include, because we want the C pre-processor
+ * to expand the macros into assembler assignment statements.
+ */
+#include "../common/asm-constants.h"
+
+#if defined(WITH_JIT)
+#include "../common/jit-config.h"
+#endif
+
+/* File: armv5te/platform.S */
+/*
+ * ===========================================================================
+ *  CPU-version-specific defines
+ * ===========================================================================
+ */
+
+/*
+ * Macro for "LDR PC,xxx", which is not allowed pre-ARMv5.  Essentially a
+ * one-way branch.
+ *
+ * May modify IP.  Does not modify LR.
+ */
+.macro  LDR_PC source
+    ldr     pc, \source
+.endm
+
+/*
+ * Macro for "MOV LR,PC / LDR PC,xxx", which is not allowed pre-ARMv5.
+ * Jump to subroutine.
+ *
+ * May modify IP and LR.
+ */
+.macro  LDR_PC_LR source
+    mov     lr, pc
+    ldr     pc, \source
+.endm
+
+/*
+ * Macro for "LDMFD SP!, {...regs...,PC}".
+ *
+ * May modify IP and LR.
+ */
+.macro  LDMFD_PC regs
+    ldmfd   sp!, {\regs,pc}
+.endm
+
+
+/* File: armv5te/entry.S */
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Interpreter entry point.
+ */
+
+/*
+ * We don't have formal stack frames, so gdb scans upward in the code
+ * to find the start of the function (a label with the %function type),
+ * and then looks at the next few instructions to figure out what
+ * got pushed onto the stack.  From this it figures out how to restore
+ * the registers, including PC, for the previous stack frame.  If gdb
+ * sees a non-function label, it stops scanning, so either we need to
+ * have nothing but assembler-local labels between the entry point and
+ * the break, or we need to fake it out.
+ *
+ * When this is defined, we add some stuff to make gdb less confused.
+ */
+#define ASSIST_DEBUGGER 1
+
+    .text
+    .align  2
+    .global dvmMterpStdRun
+    .type   dvmMterpStdRun, %function
+
+/*
+ * On entry:
+ *  r0  MterpGlue* glue
+ *
+ * This function returns a boolean "changeInterp" value.  The return comes
+ * via a call to dvmMterpStdBail().
+ */
+dvmMterpStdRun:
+#define MTERP_ENTRY1 \
+    .save {r4-r10,fp,lr}; \
+    stmfd   sp!, {r4-r10,fp,lr}         @ save 9 regs
+#define MTERP_ENTRY2 \
+    .pad    #4; \
+    sub     sp, sp, #4                  @ align 64
+
+    .fnstart
+    MTERP_ENTRY1
+    MTERP_ENTRY2
+
+    /* save stack pointer, add magic word for debuggerd */
+    str     sp, [r0, #offGlue_bailPtr]  @ save SP for eventual return
+
+    /* set up "named" registers, figure out entry point */
+    mov     rGLUE, r0                   @ set rGLUE
+    ldr     r1, [r0, #offGlue_entryPoint]   @ enum is 4 bytes in aapcs-EABI
+    LOAD_PC_FP_FROM_GLUE()              @ load rPC and rFP from "glue"
+    adr     rIBASE, dvmAsmInstructionStart  @ set rIBASE
+    cmp     r1, #kInterpEntryInstr      @ usual case?
+    bne     .Lnot_instr                 @ no, handle it
+
+#if defined(WITH_JIT)
+.Lno_singleStep:
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    /* Entry is always a possible trace start */
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_INST()
+    mov    r1, #0                       @ prepare the value for the new state
+    str    r1, [r10, #offThread_inJitCodeCache] @ back to the interp land
+    cmp    r0,#0
+    bne    common_updateProfile
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+#else
+    /* start executing the instruction at rPC */
+    FETCH_INST()                        @ load rINST from rPC
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+.Lnot_instr:
+    cmp     r1, #kInterpEntryReturn     @ were we returning from a method?
+    beq     common_returnFromMethod
+
+.Lnot_return:
+    cmp     r1, #kInterpEntryThrow      @ were we throwing an exception?
+    beq     common_exceptionThrown
+
+#if defined(WITH_JIT)
+.Lnot_throw:
+    ldr     r0,[rGLUE, #offGlue_jitResume]
+    ldr     r2,[rGLUE, #offGlue_jitResumePC]
+    cmp     r1, #kInterpEntryResume     @ resuming after Jit single-step?
+    bne     .Lbad_arg
+    cmp     rPC,r2
+    bne     .Lno_singleStep             @ must have branched, don't resume
+    mov     r1, #kInterpEntryInstr
+    str     r1, [rGLUE, #offGlue_entryPoint]
+    ldr     rINST, .LdvmCompilerTemplate
+    bx      r0                          @ re-enter the translation
+.LdvmCompilerTemplate:
+    .word   dvmCompilerTemplateStart
+#endif
+
+.Lbad_arg:
+    ldr     r0, strBadEntryPoint
+    @ r1 holds value of entryPoint
+    bl      printf
+    bl      dvmAbort
+    .fnend
+
+
+    .global dvmMterpStdBail
+    .type   dvmMterpStdBail, %function
+
+/*
+ * Restore the stack pointer and PC from the save point established on entry.
+ * This is essentially the same as a longjmp, but should be cheaper.  The
+ * last instruction causes us to return to whoever called dvmMterpStdRun.
+ *
+ * We pushed some registers on the stack in dvmMterpStdRun, then saved
+ * SP and LR.  Here we restore SP, restore the registers, and then restore
+ * LR to PC.
+ *
+ * On entry:
+ *  r0  MterpGlue* glue
+ *  r1  bool changeInterp
+ */
+dvmMterpStdBail:
+    ldr     sp, [r0, #offGlue_bailPtr]      @ sp<- saved SP
+    mov     r0, r1                          @ return the changeInterp value
+    add     sp, sp, #4                      @ un-align 64
+    LDMFD_PC "r4-r10,fp"                    @ restore 9 regs and return
+
+
+/*
+ * String references.
+ */
+strBadEntryPoint:
+    .word   .LstrBadEntryPoint
+
+
+
+    .global dvmAsmInstructionStart
+    .type   dvmAsmInstructionStart, %function
+dvmAsmInstructionStart = .L_OP_NOP
+    .text
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NOP: /* 0x00 */
+/* File: armv5te/OP_NOP.S */
+    FETCH_ADVANCE_INST(1)               @ advance to next instr, load rINST
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    GOTO_OPCODE(ip)                     @ execute it
+
+#ifdef ASSIST_DEBUGGER
+    /* insert fake function header to help gdb find the stack frame */
+    .type   dalvik_inst, %function
+dalvik_inst:
+    .fnstart
+    MTERP_ENTRY1
+    MTERP_ENTRY2
+    .fnend
+#endif
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE: /* 0x01 */
+/* File: armv6t2/OP_MOVE.S */
+    /* for move, move-object, long-to-int */
+    /* op vA, vB */
+    mov     r1, rINST, lsr #12          @ r1<- B from 15:12
+    ubfx    r0, rINST, #8, #4           @ r0<- A from 11:8
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    GET_VREG(r2, r1)                    @ r2<- fp[B]
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    SET_VREG(r2, r0)                    @ fp[A]<- r2
+    GOTO_OPCODE(ip)                     @ execute next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_FROM16: /* 0x02 */
+/* File: armv5te/OP_MOVE_FROM16.S */
+    /* for: move/from16, move-object/from16 */
+    /* op vAA, vBBBB */
+    FETCH(r1, 1)                        @ r1<- BBBB
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r2, r1)                    @ r2<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r2, r0)                    @ fp[AA]<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_16: /* 0x03 */
+/* File: armv5te/OP_MOVE_16.S */
+    /* for: move/16, move-object/16 */
+    /* op vAAAA, vBBBB */
+    FETCH(r1, 2)                        @ r1<- BBBB
+    FETCH(r0, 1)                        @ r0<- AAAA
+    FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
+    GET_VREG(r2, r1)                    @ r2<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r2, r0)                    @ fp[AAAA]<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_WIDE: /* 0x04 */
+/* File: armv6t2/OP_MOVE_WIDE.S */
+    /* move-wide vA, vB */
+    /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r2, rINST, #8, #4           @ r2<- A
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[A]
+    ldmia   r3, {r0-r1}                 @ r0/r1<- fp[B]
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r2, {r0-r1}                 @ fp[A]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_WIDE_FROM16: /* 0x05 */
+/* File: armv5te/OP_MOVE_WIDE_FROM16.S */
+    /* move-wide/from16 vAA, vBBBB */
+    /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+    FETCH(r3, 1)                        @ r3<- BBBB
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[BBBB]
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[AA]
+    ldmia   r3, {r0-r1}                 @ r0/r1<- fp[BBBB]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r2, {r0-r1}                 @ fp[AA]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_WIDE_16: /* 0x06 */
+/* File: armv5te/OP_MOVE_WIDE_16.S */
+    /* move-wide/16 vAAAA, vBBBB */
+    /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+    FETCH(r3, 2)                        @ r3<- BBBB
+    FETCH(r2, 1)                        @ r2<- AAAA
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[BBBB]
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[AAAA]
+    ldmia   r3, {r0-r1}                 @ r0/r1<- fp[BBBB]
+    FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r2, {r0-r1}                 @ fp[AAAA]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_OBJECT: /* 0x07 */
+/* File: armv5te/OP_MOVE_OBJECT.S */
+/* File: armv5te/OP_MOVE.S */
+    /* for move, move-object, long-to-int */
+    /* op vA, vB */
+    mov     r1, rINST, lsr #12          @ r1<- B from 15:12
+    mov     r0, rINST, lsr #8           @ r0<- A from 11:8
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    GET_VREG(r2, r1)                    @ r2<- fp[B]
+    and     r0, r0, #15
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    SET_VREG(r2, r0)                    @ fp[A]<- r2
+    GOTO_OPCODE(ip)                     @ execute next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_OBJECT_FROM16: /* 0x08 */
+/* File: armv5te/OP_MOVE_OBJECT_FROM16.S */
+/* File: armv5te/OP_MOVE_FROM16.S */
+    /* for: move/from16, move-object/from16 */
+    /* op vAA, vBBBB */
+    FETCH(r1, 1)                        @ r1<- BBBB
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r2, r1)                    @ r2<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r2, r0)                    @ fp[AA]<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_OBJECT_16: /* 0x09 */
+/* File: armv5te/OP_MOVE_OBJECT_16.S */
+/* File: armv5te/OP_MOVE_16.S */
+    /* for: move/16, move-object/16 */
+    /* op vAAAA, vBBBB */
+    FETCH(r1, 2)                        @ r1<- BBBB
+    FETCH(r0, 1)                        @ r0<- AAAA
+    FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
+    GET_VREG(r2, r1)                    @ r2<- fp[BBBB]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r2, r0)                    @ fp[AAAA]<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_RESULT: /* 0x0a */
+/* File: armv5te/OP_MOVE_RESULT.S */
+    /* for: move-result, move-result-object */
+    /* op vAA */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    ldr     r0, [rGLUE, #offGlue_retval]    @ r0<- glue->retval.i
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[AA]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_RESULT_WIDE: /* 0x0b */
+/* File: armv5te/OP_MOVE_RESULT_WIDE.S */
+    /* move-result-wide vAA */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    add     r3, rGLUE, #offGlue_retval  @ r3<- &glue->retval
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[AA]
+    ldmia   r3, {r0-r1}                 @ r0/r1<- retval.j
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r2, {r0-r1}                 @ fp[AA]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_RESULT_OBJECT: /* 0x0c */
+/* File: armv5te/OP_MOVE_RESULT_OBJECT.S */
+/* File: armv5te/OP_MOVE_RESULT.S */
+    /* for: move-result, move-result-object */
+    /* op vAA */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    ldr     r0, [rGLUE, #offGlue_retval]    @ r0<- glue->retval.i
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[AA]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MOVE_EXCEPTION: /* 0x0d */
+/* File: armv5te/OP_MOVE_EXCEPTION.S */
+    /* move-exception vAA */
+    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    ldr     r3, [r0, #offThread_exception]  @ r3<- dvmGetException bypass
+    mov     r1, #0                      @ r1<- 0
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    SET_VREG(r3, r2)                    @ fp[AA]<- exception obj
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r1, [r0, #offThread_exception]  @ dvmClearException bypass
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RETURN_VOID: /* 0x0e */
+/* File: armv5te/OP_RETURN_VOID.S */
+    b       common_returnFromMethod
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RETURN: /* 0x0f */
+/* File: armv5te/OP_RETURN.S */
+    /*
+     * Return a 32-bit value.  Copies the return value into the "glue"
+     * structure, then jumps to the return handler.
+     *
+     * for: return, return-object
+     */
+    /* op vAA */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    GET_VREG(r0, r2)                    @ r0<- vAA
+    str     r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
+    b       common_returnFromMethod
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RETURN_WIDE: /* 0x10 */
+/* File: armv5te/OP_RETURN_WIDE.S */
+    /*
+     * Return a 64-bit value.  Copies the return value into the "glue"
+     * structure, then jumps to the return handler.
+     */
+    /* return-wide vAA */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[AA]
+    add     r3, rGLUE, #offGlue_retval  @ r3<- &glue->retval
+    ldmia   r2, {r0-r1}                 @ r0/r1 <- vAA/vAA+1
+    stmia   r3, {r0-r1}                 @ retval<- r0/r1
+    b       common_returnFromMethod
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RETURN_OBJECT: /* 0x11 */
+/* File: armv5te/OP_RETURN_OBJECT.S */
+/* File: armv5te/OP_RETURN.S */
+    /*
+     * Return a 32-bit value.  Copies the return value into the "glue"
+     * structure, then jumps to the return handler.
+     *
+     * for: return, return-object
+     */
+    /* op vAA */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    GET_VREG(r0, r2)                    @ r0<- vAA
+    str     r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
+    b       common_returnFromMethod
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_4: /* 0x12 */
+/* File: armv6t2/OP_CONST_4.S */
+    /* const/4 vA, #+B */
+    mov     r1, rINST, lsl #16          @ r1<- Bxxx0000
+    ubfx    r0, rINST, #8, #4           @ r0<- A
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    mov     r1, r1, asr #28             @ r1<- sssssssB (sign-extended)
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    SET_VREG(r1, r0)                    @ fp[A]<- r1
+    GOTO_OPCODE(ip)                     @ execute next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_16: /* 0x13 */
+/* File: armv5te/OP_CONST_16.S */
+    /* const/16 vAA, #+BBBB */
+    FETCH_S(r0, 1)                      @ r0<- ssssBBBB (sign-extended)
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r0, r3)                    @ vAA<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST: /* 0x14 */
+/* File: armv5te/OP_CONST.S */
+    /* const vAA, #+BBBBbbbb */
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    FETCH(r0, 1)                        @ r0<- bbbb (low)
+    FETCH(r1, 2)                        @ r1<- BBBB (high)
+    FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
+    orr     r0, r0, r1, lsl #16         @ r0<- BBBBbbbb
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r3)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_HIGH16: /* 0x15 */
+/* File: armv5te/OP_CONST_HIGH16.S */
+    /* const/high16 vAA, #+BBBB0000 */
+    FETCH(r0, 1)                        @ r0<- 0000BBBB (zero-extended)
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    mov     r0, r0, lsl #16             @ r0<- BBBB0000
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r0, r3)                    @ vAA<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_WIDE_16: /* 0x16 */
+/* File: armv5te/OP_CONST_WIDE_16.S */
+    /* const-wide/16 vAA, #+BBBB */
+    FETCH_S(r0, 1)                      @ r0<- ssssBBBB (sign-extended)
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    mov     r1, r0, asr #31             @ r1<- ssssssss
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ vAA<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_WIDE_32: /* 0x17 */
+/* File: armv5te/OP_CONST_WIDE_32.S */
+    /* const-wide/32 vAA, #+BBBBbbbb */
+    FETCH(r0, 1)                        @ r0<- 0000bbbb (low)
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    FETCH_S(r2, 2)                      @ r2<- ssssBBBB (high)
+    FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
+    orr     r0, r0, r2, lsl #16         @ r0<- BBBBbbbb
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[AA]
+    mov     r1, r0, asr #31             @ r1<- ssssssss
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ vAA<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_WIDE: /* 0x18 */
+/* File: armv5te/OP_CONST_WIDE.S */
+    /* const-wide vAA, #+HHHHhhhhBBBBbbbb */
+    FETCH(r0, 1)                        @ r0<- bbbb (low)
+    FETCH(r1, 2)                        @ r1<- BBBB (low middle)
+    FETCH(r2, 3)                        @ r2<- hhhh (high middle)
+    orr     r0, r0, r1, lsl #16         @ r0<- BBBBbbbb (low word)
+    FETCH(r3, 4)                        @ r3<- HHHH (high)
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    orr     r1, r2, r3, lsl #16         @ r1<- HHHHhhhh (high word)
+    FETCH_ADVANCE_INST(5)               @ advance rPC, load rINST
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vAA<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
+/* File: armv5te/OP_CONST_WIDE_HIGH16.S */
+    /* const-wide/high16 vAA, #+BBBB000000000000 */
+    FETCH(r1, 1)                        @ r1<- 0000BBBB (zero-extended)
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    mov     r0, #0                      @ r0<- 00000000
+    mov     r1, r1, lsl #16             @ r1<- BBBB0000
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ vAA<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_STRING: /* 0x1a */
+/* File: armv5te/OP_CONST_STRING.S */
+    /* const/string vAA, String@BBBB */
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- glue->methodClassDex
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    ldr     r2, [r2, #offDvmDex_pResStrings]   @ r2<- dvmDex->pResStrings
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- pResStrings[BBBB]
+    cmp     r0, #0                      @ not yet resolved?
+    beq     .LOP_CONST_STRING_resolve
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_STRING_JUMBO: /* 0x1b */
+/* File: armv5te/OP_CONST_STRING_JUMBO.S */
+    /* const/string vAA, String@BBBBBBBB */
+    FETCH(r0, 1)                        @ r0<- bbbb (low)
+    FETCH(r1, 2)                        @ r1<- BBBB (high)
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- glue->methodClassDex
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    ldr     r2, [r2, #offDvmDex_pResStrings]   @ r2<- dvmDex->pResStrings
+    orr     r1, r0, r1, lsl #16         @ r1<- BBBBbbbb
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- pResStrings[BBBB]
+    cmp     r0, #0
+    beq     .LOP_CONST_STRING_JUMBO_resolve
+    FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CONST_CLASS: /* 0x1c */
+/* File: armv5te/OP_CONST_CLASS.S */
+    /* const/class vAA, Class@BBBB */
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- glue->methodClassDex
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    ldr     r2, [r2, #offDvmDex_pResClasses]   @ r2<- dvmDex->pResClasses
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- pResClasses[BBBB]
+    cmp     r0, #0                      @ not yet resolved?
+    beq     .LOP_CONST_CLASS_resolve
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MONITOR_ENTER: /* 0x1d */
+/* File: armv5te/OP_MONITOR_ENTER.S */
+    /*
+     * Synchronize on an object.
+     */
+    /* monitor-enter vAA */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    GET_VREG(r1, r2)                    @ r1<- vAA (object)
+    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    cmp     r1, #0                      @ null object?
+    EXPORT_PC()                         @ need for precise GC, MONITOR_TRACKING
+    beq     common_errNullObject        @ null object, throw an exception
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    bl      dvmLockObject               @ call(self, obj)
+#ifdef WITH_DEADLOCK_PREDICTION /* implies WITH_MONITOR_TRACKING */
+    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    ldr     r1, [r0, #offThread_exception] @ check for exception
+    cmp     r1, #0
+    bne     common_exceptionThrown      @ exception raised, bail out
+#endif
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MONITOR_EXIT: /* 0x1e */
+/* File: armv5te/OP_MONITOR_EXIT.S */
+    /*
+     * Unlock an object.
+     *
+     * Exceptions that occur when unlocking a monitor need to appear as
+     * if they happened at the following instruction.  See the Dalvik
+     * instruction spec.
+     */
+    /* monitor-exit vAA */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    EXPORT_PC()                         @ before fetch: export the PC
+    GET_VREG(r1, r2)                    @ r1<- vAA (object)
+    cmp     r1, #0                      @ null object?
+    beq     1f                          @ yes
+    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->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, [rGLUE, #offGlue_methodClassDex]    @ r0<- pDvmDex
+    cmp     r9, #0                      @ is object null?
+    ldr     r0, [r0, #offDvmDex_pResClasses]    @ r0<- pDvmDex->pResClasses
+    beq     .LOP_CHECK_CAST_okay            @ null obj, cast always succeeds
+    ldr     r1, [r0, r2, lsl #2]        @ r1<- resolved class
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
+    cmp     r1, #0                      @ have we resolved this before?
+    beq     .LOP_CHECK_CAST_resolve         @ not resolved, do it now
+.LOP_CHECK_CAST_resolved:
+    cmp     r0, r1                      @ same class (trivial success)?
+    bne     .LOP_CHECK_CAST_fullcheck       @ no, do full check
+.LOP_CHECK_CAST_okay:
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INSTANCE_OF: /* 0x20 */
+/* File: armv5te/OP_INSTANCE_OF.S */
+    /*
+     * Check to see if an object reference is an instance of a class.
+     *
+     * Most common situation is a non-null object, being compared against
+     * an already-resolved class.
+     */
+    /* instance-of vA, vB, class@CCCC */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    GET_VREG(r0, r3)                    @ r0<- vB (object)
+    and     r9, r9, #15                 @ r9<- A
+    cmp     r0, #0                      @ is object null?
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- pDvmDex
+    beq     .LOP_INSTANCE_OF_store           @ null obj, not an instance, store r0
+    FETCH(r3, 1)                        @ r3<- CCCC
+    ldr     r2, [r2, #offDvmDex_pResClasses]    @ r2<- pDvmDex->pResClasses
+    ldr     r1, [r2, r3, lsl #2]        @ r1<- resolved class
+    ldr     r0, [r0, #offObject_clazz]  @ r0<- obj->clazz
+    cmp     r1, #0                      @ have we resolved this before?
+    beq     .LOP_INSTANCE_OF_resolve         @ not resolved, do it now
+.LOP_INSTANCE_OF_resolved: @ r0=obj->clazz, r1=resolved class
+    cmp     r0, r1                      @ same class (trivial success)?
+    beq     .LOP_INSTANCE_OF_trivial         @ yes, trivial finish
+    b       .LOP_INSTANCE_OF_fullcheck       @ no, do full check
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ARRAY_LENGTH: /* 0x21 */
+/* File: armv6t2/OP_ARRAY_LENGTH.S */
+    /*
+     * Return the length of an array.
+     */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r2, rINST, #8, #4           @ r2<- A
+    GET_VREG(r0, r1)                    @ r0<- vB (object ref)
+    cmp     r0, #0                      @ is object null?
+    beq     common_errNullObject        @ yup, fail
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- array length
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r3, r2)                    @ vB<- length
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_INSTANCE: /* 0x22 */
+/* File: armv5te/OP_NEW_INSTANCE.S */
+    /*
+     * Create a new instance of a class.
+     */
+    /* new-instance vAA, class@BBBB */
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved class
+    EXPORT_PC()                         @ req'd for init, resolve, alloc
+    cmp     r0, #0                      @ already resolved?
+    beq     .LOP_NEW_INSTANCE_resolve         @ no, resolve it now
+.LOP_NEW_INSTANCE_resolved:   @ r0=class
+    ldrb    r1, [r0, #offClassObject_status]    @ r1<- ClassStatus enum
+    cmp     r1, #CLASS_INITIALIZED      @ has class been initialized?
+    bne     .LOP_NEW_INSTANCE_needinit        @ no, init class now
+.LOP_NEW_INSTANCE_initialized: @ r0=class
+    mov     r1, #ALLOC_DONT_TRACK       @ flags for alloc call
+    bl      dvmAllocObject              @ r0<- new object
+    b       .LOP_NEW_INSTANCE_finish          @ continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEW_ARRAY: /* 0x23 */
+/* File: armv5te/OP_NEW_ARRAY.S */
+    /*
+     * Allocate an array of objects, specified with the array class
+     * and a count.
+     *
+     * The verifier guarantees that this is an array class, so we don't
+     * check for it here.
+     */
+    /* new-array vA, vB, class@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    FETCH(r2, 1)                        @ r2<- CCCC
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- pDvmDex
+    GET_VREG(r1, r0)                    @ r1<- vB (array length)
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    cmp     r1, #0                      @ check length
+    ldr     r0, [r3, r2, lsl #2]        @ r0<- resolved class
+    bmi     common_errNegativeArraySize @ negative length, bail
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ req'd for resolve, alloc
+    bne     .LOP_NEW_ARRAY_finish          @ resolved, continue
+    b       .LOP_NEW_ARRAY_resolve         @ do resolve now
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FILLED_NEW_ARRAY: /* 0x24 */
+/* File: armv5te/OP_FILLED_NEW_ARRAY.S */
+    /*
+     * Create a new array with elements filled from registers.
+     *
+     * for: filled-new-array, filled-new-array/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, type@BBBB */
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    EXPORT_PC()                         @ need for resolve and alloc
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved class
+    mov     r10, rINST, lsr #8          @ r10<- AA or BA
+    cmp     r0, #0                      @ already resolved?
+    bne     .LOP_FILLED_NEW_ARRAY_continue        @ yes, continue on
+8:  ldr     r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+    mov     r2, #0                      @ r2<- false
+    ldr     r0, [r3, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveClass             @ r0<- call(clazz, ref)
+    cmp     r0, #0                      @ got null?
+    beq     common_exceptionThrown      @ yes, handle exception
+    b       .LOP_FILLED_NEW_ARRAY_continue
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
+/* File: armv5te/OP_FILLED_NEW_ARRAY_RANGE.S */
+/* File: armv5te/OP_FILLED_NEW_ARRAY.S */
+    /*
+     * Create a new array with elements filled from registers.
+     *
+     * for: filled-new-array, filled-new-array/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, type@BBBB */
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResClasses]    @ r3<- pDvmDex->pResClasses
+    EXPORT_PC()                         @ need for resolve and alloc
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved class
+    mov     r10, rINST, lsr #8          @ r10<- AA or BA
+    cmp     r0, #0                      @ already resolved?
+    bne     .LOP_FILLED_NEW_ARRAY_RANGE_continue        @ yes, continue on
+8:  ldr     r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+    mov     r2, #0                      @ r2<- false
+    ldr     r0, [r3, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveClass             @ r0<- call(clazz, ref)
+    cmp     r0, #0                      @ got null?
+    beq     common_exceptionThrown      @ yes, handle exception
+    b       .LOP_FILLED_NEW_ARRAY_RANGE_continue
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FILL_ARRAY_DATA: /* 0x26 */
+/* File: armv5te/OP_FILL_ARRAY_DATA.S */
+    /* fill-array-data vAA, +BBBBBBBB */
+    FETCH(r0, 1)                        @ r0<- bbbb (lo)
+    FETCH(r1, 2)                        @ r1<- BBBB (hi)
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    orr     r1, r0, r1, lsl #16         @ r1<- BBBBbbbb
+    GET_VREG(r0, r3)                    @ r0<- vAA (array object)
+    add     r1, rPC, r1, lsl #1         @ r1<- PC + BBBBbbbb*2 (array data off.)
+    EXPORT_PC();
+    bl      dvmInterpHandleFillArrayData@ fill the array with predefined data
+    cmp     r0, #0                      @ 0 means an exception is thrown
+    beq     common_exceptionThrown      @ has exception
+    FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_THROW: /* 0x27 */
+/* File: armv5te/OP_THROW.S */
+    /*
+     * Throw an exception object in the current thread.
+     */
+    /* throw vAA */
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    GET_VREG(r1, r2)                    @ r1<- vAA (exception object)
+    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    cmp     r1, #0                      @ null object?
+    beq     common_errNullObject        @ yes, throw an NPE instead
+    @ bypass dvmSetException, just store it
+    str     r1, [r0, #offThread_exception]  @ thread->exception<- obj
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_GOTO: /* 0x28 */
+/* File: armv5te/OP_GOTO.S */
+    /*
+     * Unconditional branch, 8-bit offset.
+     *
+     * The branch distance is a signed code-unit offset, which we need to
+     * double to get a byte offset.
+     */
+    /* goto +AA */
+    mov     r0, rINST, lsl #16          @ r0<- AAxx0000
+    movs    r9, r0, asr #24             @ r9<- ssssssAA (sign-extended)
+    mov     r9, r9, lsl #1              @ r9<- byte offset
+    bmi     common_backwardBranch       @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    cmp     r0,#0
+    bne     common_updateProfile
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_GOTO_16: /* 0x29 */
+/* File: armv5te/OP_GOTO_16.S */
+    /*
+     * Unconditional branch, 16-bit offset.
+     *
+     * The branch distance is a signed code-unit offset, which we need to
+     * double to get a byte offset.
+     */
+    /* goto/16 +AAAA */
+    FETCH_S(r0, 1)                      @ r0<- ssssAAAA (sign-extended)
+    movs    r9, r0, asl #1              @ r9<- byte offset, check sign
+    bmi     common_backwardBranch       @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    cmp     r0,#0
+    bne     common_updateProfile
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_GOTO_32: /* 0x2a */
+/* File: armv5te/OP_GOTO_32.S */
+    /*
+     * Unconditional branch, 32-bit offset.
+     *
+     * The branch distance is a signed code-unit offset, which we need to
+     * double to get a byte offset.
+     *
+     * Unlike most opcodes, this one is allowed to branch to itself, so
+     * our "backward branch" test must be "<=0" instead of "<0".  The ORRS
+     * instruction doesn't affect the V flag, so we need to clear it
+     * explicitly.
+     */
+    /* goto/32 +AAAAAAAA */
+    FETCH(r0, 1)                        @ r0<- aaaa (lo)
+    FETCH(r1, 2)                        @ r1<- AAAA (hi)
+    cmp     ip, ip                      @ (clear V flag during stall)
+    orrs    r0, r0, r1, lsl #16         @ r0<- AAAAaaaa, check sign
+    mov     r9, r0, asl #1              @ r9<- byte offset
+    ble     common_backwardBranch       @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    cmp     r0,#0
+    bne     common_updateProfile
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_PACKED_SWITCH: /* 0x2b */
+/* File: armv5te/OP_PACKED_SWITCH.S */
+    /*
+     * Handle a packed-switch or sparse-switch instruction.  In both cases
+     * we decode it and hand it off to a helper function.
+     *
+     * We don't really expect backward branches in a switch statement, but
+     * they're perfectly legal, so we check for them here.
+     *
+     * for: packed-switch, sparse-switch
+     */
+    /* op vAA, +BBBB */
+    FETCH(r0, 1)                        @ r0<- bbbb (lo)
+    FETCH(r1, 2)                        @ r1<- BBBB (hi)
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    orr     r0, r0, r1, lsl #16         @ r0<- BBBBbbbb
+    GET_VREG(r1, r3)                    @ r1<- vAA
+    add     r0, rPC, r0, lsl #1         @ r0<- PC + BBBBbbbb*2
+    bl      dvmInterpHandlePackedSwitch                       @ r0<- code-unit branch offset
+    movs    r9, r0, asl #1              @ r9<- branch byte offset, check sign
+    bmi     common_backwardBranch       @ backward branch, do periodic checks
+    beq     common_backwardBranch       @ (want to use BLE but V is unknown)
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    cmp     r0,#0
+    bne     common_updateProfile
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPARSE_SWITCH: /* 0x2c */
+/* File: armv5te/OP_SPARSE_SWITCH.S */
+/* File: armv5te/OP_PACKED_SWITCH.S */
+    /*
+     * Handle a packed-switch or sparse-switch instruction.  In both cases
+     * we decode it and hand it off to a helper function.
+     *
+     * We don't really expect backward branches in a switch statement, but
+     * they're perfectly legal, so we check for them here.
+     *
+     * for: packed-switch, sparse-switch
+     */
+    /* op vAA, +BBBB */
+    FETCH(r0, 1)                        @ r0<- bbbb (lo)
+    FETCH(r1, 2)                        @ r1<- BBBB (hi)
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    orr     r0, r0, r1, lsl #16         @ r0<- BBBBbbbb
+    GET_VREG(r1, r3)                    @ r1<- vAA
+    add     r0, rPC, r0, lsl #1         @ r0<- PC + BBBBbbbb*2
+    bl      dvmInterpHandleSparseSwitch                       @ r0<- code-unit branch offset
+    movs    r9, r0, asl #1              @ r9<- branch byte offset, check sign
+    bmi     common_backwardBranch       @ backward branch, do periodic checks
+    beq     common_backwardBranch       @ (want to use BLE but V is unknown)
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    cmp     r0,#0
+    bne     common_updateProfile
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMPL_FLOAT: /* 0x2d */
+/* File: arm-vfp/OP_CMPL_FLOAT.S */
+    /*
+     * Compare two floating-point values.  Puts 0, 1, or -1 into the
+     * destination register based on the results of the comparison.
+     *
+     * int compare(x, y) {
+     *     if (x == y) {
+     *         return 0;
+     *     } else if (x > y) {
+     *         return 1;
+     *     } else if (x < y) {
+     *         return -1;
+     *     } else {
+     *         return -1;
+     *     }
+     * }
+     */
+    /* op vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    VREG_INDEX_TO_ADDR(r2, r2)          @ r2<- &vBB
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vCC
+    flds    s0, [r2]                    @ s0<- vBB
+    flds    s1, [r3]                    @ s1<- vCC
+    fcmpes  s0, s1                      @ compare (vBB, vCC)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    mvn     r0, #0                      @ r0<- -1 (default)
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    fmstat                              @ export status flags
+    movgt   r0, #1                      @ (greater than) r1<- 1
+    moveq   r0, #0                      @ (equal) r1<- 0
+    b       .LOP_CMPL_FLOAT_finish          @ argh
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMPG_FLOAT: /* 0x2e */
+/* File: arm-vfp/OP_CMPG_FLOAT.S */
+    /*
+     * Compare two floating-point values.  Puts 0, 1, or -1 into the
+     * destination register based on the results of the comparison.
+     *
+     * int compare(x, y) {
+     *     if (x == y) {
+     *         return 0;
+     *     } else if (x < y) {
+     *         return -1;
+     *     } else if (x > y) {
+     *         return 1;
+     *     } else {
+     *         return 1;
+     *     }
+     * }
+     */
+    /* op vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    VREG_INDEX_TO_ADDR(r2, r2)          @ r2<- &vBB
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vCC
+    flds    s0, [r2]                    @ s0<- vBB
+    flds    s1, [r3]                    @ s1<- vCC
+    fcmpes  s0, s1                      @ compare (vBB, vCC)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    mov     r0, #1                      @ r0<- 1 (default)
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    fmstat                              @ export status flags
+    mvnmi   r0, #0                      @ (less than) r1<- -1
+    moveq   r0, #0                      @ (equal) r1<- 0
+    b       .LOP_CMPG_FLOAT_finish          @ argh
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMPL_DOUBLE: /* 0x2f */
+/* File: arm-vfp/OP_CMPL_DOUBLE.S */
+    /*
+     * Compare two floating-point values.  Puts 0, 1, or -1 into the
+     * destination register based on the results of the comparison.
+     *
+     * int compare(x, y) {
+     *     if (x == y) {
+     *         return 0;
+     *     } else if (x > y) {
+     *         return 1;
+     *     } else if (x < y) {
+     *         return -1;
+     *     } else {
+     *         return -1;
+     *     }
+     * }
+     */
+    /* op vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    VREG_INDEX_TO_ADDR(r2, r2)          @ r2<- &vBB
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vCC
+    fldd    d0, [r2]                    @ d0<- vBB
+    fldd    d1, [r3]                    @ d1<- vCC
+    fcmped  d0, d1                      @ compare (vBB, vCC)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    mvn     r0, #0                      @ r0<- -1 (default)
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    fmstat                              @ export status flags
+    movgt   r0, #1                      @ (greater than) r1<- 1
+    moveq   r0, #0                      @ (equal) r1<- 0
+    b       .LOP_CMPL_DOUBLE_finish          @ argh
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMPG_DOUBLE: /* 0x30 */
+/* File: arm-vfp/OP_CMPG_DOUBLE.S */
+    /*
+     * Compare two floating-point values.  Puts 0, 1, or -1 into the
+     * destination register based on the results of the comparison.
+     *
+     * int compare(x, y) {
+     *     if (x == y) {
+     *         return 0;
+     *     } else if (x < y) {
+     *         return -1;
+     *     } else if (x > y) {
+     *         return 1;
+     *     } else {
+     *         return 1;
+     *     }
+     * }
+     */
+    /* op vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    VREG_INDEX_TO_ADDR(r2, r2)          @ r2<- &vBB
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vCC
+    fldd    d0, [r2]                    @ d0<- vBB
+    fldd    d1, [r3]                    @ d1<- vCC
+    fcmped  d0, d1                      @ compare (vBB, vCC)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    mov     r0, #1                      @ r0<- 1 (default)
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    fmstat                              @ export status flags
+    mvnmi   r0, #0                      @ (less than) r1<- -1
+    moveq   r0, #0                      @ (equal) r1<- 0
+    b       .LOP_CMPG_DOUBLE_finish          @ argh
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_CMP_LONG: /* 0x31 */
+/* File: armv5te/OP_CMP_LONG.S */
+    /*
+     * Compare two 64-bit values.  Puts 0, 1, or -1 into the destination
+     * register based on the results of the comparison.
+     *
+     * We load the full values with LDM, but in practice many values could
+     * be resolved by only looking at the high word.  This could be made
+     * faster or slower by splitting the LDM into a pair of LDRs.
+     *
+     * If we just wanted to set condition flags, we could do this:
+     *  subs    ip, r0, r2
+     *  sbcs    ip, r1, r3
+     *  subeqs  ip, r0, r2
+     * Leaving { <0, 0, >0 } in ip.  However, we have to set it to a specific
+     * integer value, which we can do with 2 conditional mov/mvn instructions
+     * (set 1, set -1; if they're equal we already have 0 in ip), giving
+     * us a constant 5-cycle path plus a branch at the end to the
+     * instruction epilogue code.  The multi-compare approach below needs
+     * 2 or 3 cycles + branch if the high word doesn't match, 6 + branch
+     * in the worst case (the 64-bit values are equal).
+     */
+    /* cmp-long vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
+    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    cmp     r1, r3                      @ compare (vBB+1, vCC+1)
+    blt     .LOP_CMP_LONG_less            @ signed compare on high part
+    bgt     .LOP_CMP_LONG_greater
+    subs    r1, r0, r2                  @ r1<- r0 - r2
+    bhi     .LOP_CMP_LONG_greater         @ unsigned compare on low part
+    bne     .LOP_CMP_LONG_less
+    b       .LOP_CMP_LONG_finish          @ equal; r1 already holds 0
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_EQ: /* 0x32 */
+/* File: armv6t2/OP_IF_EQ.S */
+/* File: armv6t2/bincmp.S */
+    /*
+     * Generic two-operand compare-and-branch operation.  Provide a "revcmp"
+     * fragment that specifies the *reverse* comparison to perform, e.g.
+     * for "if-le" you would use "gt".
+     *
+     * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+     */
+    /* if-cmp vA, vB, +CCCC */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r0, rINST, #8, #4           @ r0<- A
+    GET_VREG(r3, r1)                    @ r3<- vB
+    GET_VREG(r2, r0)                    @ r2<- vA
+    mov     r9, #4                      @ r0<- BYTE branch dist for not-taken
+    cmp     r2, r3                      @ compare (vA, vB)
+    bne  1f                      @ branch to 1 if comparison failed
+    FETCH_S(r9, 1)                      @ r9<- branch offset, in code units
+    movs    r9, r9, asl #1              @ convert to bytes, check sign
+    bmi     common_backwardBranch       @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    b        common_testUpdateProfile
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_NE: /* 0x33 */
+/* File: armv6t2/OP_IF_NE.S */
+/* File: armv6t2/bincmp.S */
+    /*
+     * Generic two-operand compare-and-branch operation.  Provide a "revcmp"
+     * fragment that specifies the *reverse* comparison to perform, e.g.
+     * for "if-le" you would use "gt".
+     *
+     * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+     */
+    /* if-cmp vA, vB, +CCCC */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r0, rINST, #8, #4           @ r0<- A
+    GET_VREG(r3, r1)                    @ r3<- vB
+    GET_VREG(r2, r0)                    @ r2<- vA
+    mov     r9, #4                      @ r0<- BYTE branch dist for not-taken
+    cmp     r2, r3                      @ compare (vA, vB)
+    beq  1f                      @ branch to 1 if comparison failed
+    FETCH_S(r9, 1)                      @ r9<- branch offset, in code units
+    movs    r9, r9, asl #1              @ convert to bytes, check sign
+    bmi     common_backwardBranch       @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    b        common_testUpdateProfile
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_LT: /* 0x34 */
+/* File: armv6t2/OP_IF_LT.S */
+/* File: armv6t2/bincmp.S */
+    /*
+     * Generic two-operand compare-and-branch operation.  Provide a "revcmp"
+     * fragment that specifies the *reverse* comparison to perform, e.g.
+     * for "if-le" you would use "gt".
+     *
+     * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+     */
+    /* if-cmp vA, vB, +CCCC */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r0, rINST, #8, #4           @ r0<- A
+    GET_VREG(r3, r1)                    @ r3<- vB
+    GET_VREG(r2, r0)                    @ r2<- vA
+    mov     r9, #4                      @ r0<- BYTE branch dist for not-taken
+    cmp     r2, r3                      @ compare (vA, vB)
+    bge  1f                      @ branch to 1 if comparison failed
+    FETCH_S(r9, 1)                      @ r9<- branch offset, in code units
+    movs    r9, r9, asl #1              @ convert to bytes, check sign
+    bmi     common_backwardBranch       @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    b        common_testUpdateProfile
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_GE: /* 0x35 */
+/* File: armv6t2/OP_IF_GE.S */
+/* File: armv6t2/bincmp.S */
+    /*
+     * Generic two-operand compare-and-branch operation.  Provide a "revcmp"
+     * fragment that specifies the *reverse* comparison to perform, e.g.
+     * for "if-le" you would use "gt".
+     *
+     * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+     */
+    /* if-cmp vA, vB, +CCCC */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r0, rINST, #8, #4           @ r0<- A
+    GET_VREG(r3, r1)                    @ r3<- vB
+    GET_VREG(r2, r0)                    @ r2<- vA
+    mov     r9, #4                      @ r0<- BYTE branch dist for not-taken
+    cmp     r2, r3                      @ compare (vA, vB)
+    blt  1f                      @ branch to 1 if comparison failed
+    FETCH_S(r9, 1)                      @ r9<- branch offset, in code units
+    movs    r9, r9, asl #1              @ convert to bytes, check sign
+    bmi     common_backwardBranch       @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    b        common_testUpdateProfile
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_GT: /* 0x36 */
+/* File: armv6t2/OP_IF_GT.S */
+/* File: armv6t2/bincmp.S */
+    /*
+     * Generic two-operand compare-and-branch operation.  Provide a "revcmp"
+     * fragment that specifies the *reverse* comparison to perform, e.g.
+     * for "if-le" you would use "gt".
+     *
+     * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+     */
+    /* if-cmp vA, vB, +CCCC */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r0, rINST, #8, #4           @ r0<- A
+    GET_VREG(r3, r1)                    @ r3<- vB
+    GET_VREG(r2, r0)                    @ r2<- vA
+    mov     r9, #4                      @ r0<- BYTE branch dist for not-taken
+    cmp     r2, r3                      @ compare (vA, vB)
+    ble  1f                      @ branch to 1 if comparison failed
+    FETCH_S(r9, 1)                      @ r9<- branch offset, in code units
+    movs    r9, r9, asl #1              @ convert to bytes, check sign
+    bmi     common_backwardBranch       @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    b        common_testUpdateProfile
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_LE: /* 0x37 */
+/* File: armv6t2/OP_IF_LE.S */
+/* File: armv6t2/bincmp.S */
+    /*
+     * Generic two-operand compare-and-branch operation.  Provide a "revcmp"
+     * fragment that specifies the *reverse* comparison to perform, e.g.
+     * for "if-le" you would use "gt".
+     *
+     * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+     */
+    /* if-cmp vA, vB, +CCCC */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r0, rINST, #8, #4           @ r0<- A
+    GET_VREG(r3, r1)                    @ r3<- vB
+    GET_VREG(r2, r0)                    @ r2<- vA
+    mov     r9, #4                      @ r0<- BYTE branch dist for not-taken
+    cmp     r2, r3                      @ compare (vA, vB)
+    bgt  1f                      @ branch to 1 if comparison failed
+    FETCH_S(r9, 1)                      @ r9<- branch offset, in code units
+    movs    r9, r9, asl #1              @ convert to bytes, check sign
+    bmi     common_backwardBranch       @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    b        common_testUpdateProfile
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_EQZ: /* 0x38 */
+/* File: armv5te/OP_IF_EQZ.S */
+/* File: armv5te/zcmp.S */
+    /*
+     * Generic one-operand compare-and-branch operation.  Provide a "revcmp"
+     * fragment that specifies the *reverse* comparison to perform, e.g.
+     * for "if-le" you would use "gt".
+     *
+     * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+     */
+    /* if-cmp vAA, +BBBB */
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    GET_VREG(r2, r0)                    @ r2<- vAA
+    mov     r9, #4                      @ r0<- BYTE branch dist for not-taken
+    cmp     r2, #0                      @ compare (vA, 0)
+    bne  1f                      @ branch to 1 if comparison failed
+    FETCH_S(r9, 1)                      @ r9<- branch offset, in code units
+    movs    r9, r9, asl #1              @ convert to bytes, check sign
+    bmi     common_backwardBranch       @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    cmp     r0,#0
+    bne     common_updateProfile
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_NEZ: /* 0x39 */
+/* File: armv5te/OP_IF_NEZ.S */
+/* File: armv5te/zcmp.S */
+    /*
+     * Generic one-operand compare-and-branch operation.  Provide a "revcmp"
+     * fragment that specifies the *reverse* comparison to perform, e.g.
+     * for "if-le" you would use "gt".
+     *
+     * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+     */
+    /* if-cmp vAA, +BBBB */
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    GET_VREG(r2, r0)                    @ r2<- vAA
+    mov     r9, #4                      @ r0<- BYTE branch dist for not-taken
+    cmp     r2, #0                      @ compare (vA, 0)
+    beq  1f                      @ branch to 1 if comparison failed
+    FETCH_S(r9, 1)                      @ r9<- branch offset, in code units
+    movs    r9, r9, asl #1              @ convert to bytes, check sign
+    bmi     common_backwardBranch       @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    cmp     r0,#0
+    bne     common_updateProfile
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_LTZ: /* 0x3a */
+/* File: armv5te/OP_IF_LTZ.S */
+/* File: armv5te/zcmp.S */
+    /*
+     * Generic one-operand compare-and-branch operation.  Provide a "revcmp"
+     * fragment that specifies the *reverse* comparison to perform, e.g.
+     * for "if-le" you would use "gt".
+     *
+     * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+     */
+    /* if-cmp vAA, +BBBB */
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    GET_VREG(r2, r0)                    @ r2<- vAA
+    mov     r9, #4                      @ r0<- BYTE branch dist for not-taken
+    cmp     r2, #0                      @ compare (vA, 0)
+    bge  1f                      @ branch to 1 if comparison failed
+    FETCH_S(r9, 1)                      @ r9<- branch offset, in code units
+    movs    r9, r9, asl #1              @ convert to bytes, check sign
+    bmi     common_backwardBranch       @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    cmp     r0,#0
+    bne     common_updateProfile
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_GEZ: /* 0x3b */
+/* File: armv5te/OP_IF_GEZ.S */
+/* File: armv5te/zcmp.S */
+    /*
+     * Generic one-operand compare-and-branch operation.  Provide a "revcmp"
+     * fragment that specifies the *reverse* comparison to perform, e.g.
+     * for "if-le" you would use "gt".
+     *
+     * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+     */
+    /* if-cmp vAA, +BBBB */
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    GET_VREG(r2, r0)                    @ r2<- vAA
+    mov     r9, #4                      @ r0<- BYTE branch dist for not-taken
+    cmp     r2, #0                      @ compare (vA, 0)
+    blt  1f                      @ branch to 1 if comparison failed
+    FETCH_S(r9, 1)                      @ r9<- branch offset, in code units
+    movs    r9, r9, asl #1              @ convert to bytes, check sign
+    bmi     common_backwardBranch       @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    cmp     r0,#0
+    bne     common_updateProfile
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_GTZ: /* 0x3c */
+/* File: armv5te/OP_IF_GTZ.S */
+/* File: armv5te/zcmp.S */
+    /*
+     * Generic one-operand compare-and-branch operation.  Provide a "revcmp"
+     * fragment that specifies the *reverse* comparison to perform, e.g.
+     * for "if-le" you would use "gt".
+     *
+     * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+     */
+    /* if-cmp vAA, +BBBB */
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    GET_VREG(r2, r0)                    @ r2<- vAA
+    mov     r9, #4                      @ r0<- BYTE branch dist for not-taken
+    cmp     r2, #0                      @ compare (vA, 0)
+    ble  1f                      @ branch to 1 if comparison failed
+    FETCH_S(r9, 1)                      @ r9<- branch offset, in code units
+    movs    r9, r9, asl #1              @ convert to bytes, check sign
+    bmi     common_backwardBranch       @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    cmp     r0,#0
+    bne     common_updateProfile
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IF_LEZ: /* 0x3d */
+/* File: armv5te/OP_IF_LEZ.S */
+/* File: armv5te/zcmp.S */
+    /*
+     * Generic one-operand compare-and-branch operation.  Provide a "revcmp"
+     * fragment that specifies the *reverse* comparison to perform, e.g.
+     * for "if-le" you would use "gt".
+     *
+     * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+     */
+    /* if-cmp vAA, +BBBB */
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    GET_VREG(r2, r0)                    @ r2<- vAA
+    mov     r9, #4                      @ r0<- BYTE branch dist for not-taken
+    cmp     r2, #0                      @ compare (vA, 0)
+    bgt  1f                      @ branch to 1 if comparison failed
+    FETCH_S(r9, 1)                      @ r9<- branch offset, in code units
+    movs    r9, r9, asl #1              @ convert to bytes, check sign
+    bmi     common_backwardBranch       @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    cmp     r0,#0
+    bne     common_updateProfile
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3E: /* 0x3e */
+/* File: armv5te/OP_UNUSED_3E.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_3F: /* 0x3f */
+/* File: armv5te/OP_UNUSED_3F.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_40: /* 0x40 */
+/* File: armv5te/OP_UNUSED_40.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_41: /* 0x41 */
+/* File: armv5te/OP_UNUSED_41.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_42: /* 0x42 */
+/* File: armv5te/OP_UNUSED_42.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_43: /* 0x43 */
+/* File: armv5te/OP_UNUSED_43.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET: /* 0x44 */
+/* File: armv5te/OP_AGET.S */
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+     * instructions.  We use a pair of FETCH_Bs instead.
+     *
+     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     */
+    /* op vAA, vBB, vCC */
+    FETCH_B(r2, 1, 0)                   @ r2<- BB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    FETCH_B(r3, 1, 1)                   @ r3<- CC
+    GET_VREG(r0, r2)                    @ r0<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     r0, #0                      @ null array object?
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r0, r0, r1, lsl #2     @ r0<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    bcs     common_errArrayIndex        @ index >= length, bail
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldr   r2, [r0, #offArrayObject_contents]  @ r2<- vBB[vCC]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r2, r9)                    @ vAA<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET_WIDE: /* 0x45 */
+/* File: armv5te/OP_AGET_WIDE.S */
+    /*
+     * Array get, 64 bits.  vAA <- vBB[vCC].
+     *
+     * Arrays of long/double are 64-bit aligned, so it's okay to use LDRD.
+     */
+    /* aget-wide vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    GET_VREG(r0, r2)                    @ r0<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     r0, #0                      @ null array object?
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r0, r0, r1, lsl #3          @ r0<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    bcc     .LOP_AGET_WIDE_finish          @ okay, continue below
+    b       common_errArrayIndex        @ index >= length, bail
+    @ May want to swap the order of these two branches depending on how the
+    @ branch prediction (if any) handles conditional forward branches vs.
+    @ unconditional forward branches.
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET_OBJECT: /* 0x46 */
+/* File: armv5te/OP_AGET_OBJECT.S */
+/* File: armv5te/OP_AGET.S */
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+     * instructions.  We use a pair of FETCH_Bs instead.
+     *
+     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     */
+    /* op vAA, vBB, vCC */
+    FETCH_B(r2, 1, 0)                   @ r2<- BB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    FETCH_B(r3, 1, 1)                   @ r3<- CC
+    GET_VREG(r0, r2)                    @ r0<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     r0, #0                      @ null array object?
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r0, r0, r1, lsl #2     @ r0<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    bcs     common_errArrayIndex        @ index >= length, bail
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldr   r2, [r0, #offArrayObject_contents]  @ r2<- vBB[vCC]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r2, r9)                    @ vAA<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET_BOOLEAN: /* 0x47 */
+/* File: armv5te/OP_AGET_BOOLEAN.S */
+/* File: armv5te/OP_AGET.S */
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+     * instructions.  We use a pair of FETCH_Bs instead.
+     *
+     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     */
+    /* op vAA, vBB, vCC */
+    FETCH_B(r2, 1, 0)                   @ r2<- BB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    FETCH_B(r3, 1, 1)                   @ r3<- CC
+    GET_VREG(r0, r2)                    @ r0<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     r0, #0                      @ null array object?
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r0, r0, r1, lsl #0     @ r0<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    bcs     common_errArrayIndex        @ index >= length, bail
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldrb   r2, [r0, #offArrayObject_contents]  @ r2<- vBB[vCC]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r2, r9)                    @ vAA<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET_BYTE: /* 0x48 */
+/* File: armv5te/OP_AGET_BYTE.S */
+/* File: armv5te/OP_AGET.S */
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+     * instructions.  We use a pair of FETCH_Bs instead.
+     *
+     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     */
+    /* op vAA, vBB, vCC */
+    FETCH_B(r2, 1, 0)                   @ r2<- BB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    FETCH_B(r3, 1, 1)                   @ r3<- CC
+    GET_VREG(r0, r2)                    @ r0<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     r0, #0                      @ null array object?
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r0, r0, r1, lsl #0     @ r0<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    bcs     common_errArrayIndex        @ index >= length, bail
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldrsb   r2, [r0, #offArrayObject_contents]  @ r2<- vBB[vCC]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r2, r9)                    @ vAA<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET_CHAR: /* 0x49 */
+/* File: armv5te/OP_AGET_CHAR.S */
+/* File: armv5te/OP_AGET.S */
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+     * instructions.  We use a pair of FETCH_Bs instead.
+     *
+     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     */
+    /* op vAA, vBB, vCC */
+    FETCH_B(r2, 1, 0)                   @ r2<- BB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    FETCH_B(r3, 1, 1)                   @ r3<- CC
+    GET_VREG(r0, r2)                    @ r0<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     r0, #0                      @ null array object?
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r0, r0, r1, lsl #1     @ r0<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    bcs     common_errArrayIndex        @ index >= length, bail
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldrh   r2, [r0, #offArrayObject_contents]  @ r2<- vBB[vCC]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r2, r9)                    @ vAA<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AGET_SHORT: /* 0x4a */
+/* File: armv5te/OP_AGET_SHORT.S */
+/* File: armv5te/OP_AGET.S */
+    /*
+     * Array get, 32 bits or less.  vAA <- vBB[vCC].
+     *
+     * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+     * instructions.  We use a pair of FETCH_Bs instead.
+     *
+     * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+     */
+    /* op vAA, vBB, vCC */
+    FETCH_B(r2, 1, 0)                   @ r2<- BB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    FETCH_B(r3, 1, 1)                   @ r3<- CC
+    GET_VREG(r0, r2)                    @ r0<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     r0, #0                      @ null array object?
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r0, r0, r1, lsl #1     @ r0<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    bcs     common_errArrayIndex        @ index >= length, bail
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldrsh   r2, [r0, #offArrayObject_contents]  @ r2<- vBB[vCC]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r2, r9)                    @ vAA<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT: /* 0x4b */
+/* File: armv5te/OP_APUT.S */
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA.
+     *
+     * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+     * instructions.  We use a pair of FETCH_Bs instead.
+     *
+     * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+     */
+    /* op vAA, vBB, vCC */
+    FETCH_B(r2, 1, 0)                   @ r2<- BB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    FETCH_B(r3, 1, 1)                   @ r3<- CC
+    GET_VREG(r0, r2)                    @ r0<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     r0, #0                      @ null array object?
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r0, r0, r1, lsl #2     @ r0<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    bcs     common_errArrayIndex        @ index >= length, bail
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r2, r9)                    @ r2<- vAA
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str  r2, [r0, #offArrayObject_contents]  @ vBB[vCC]<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT_WIDE: /* 0x4c */
+/* File: armv5te/OP_APUT_WIDE.S */
+    /*
+     * Array put, 64 bits.  vBB[vCC] <- vAA.
+     *
+     * Arrays of long/double are 64-bit aligned, so it's okay to use STRD.
+     */
+    /* aput-wide vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    GET_VREG(r0, r2)                    @ r0<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     r0, #0                      @ null array object?
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r0, r0, r1, lsl #3          @ r0<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    bcc     .LOP_APUT_WIDE_finish          @ okay, continue below
+    b       common_errArrayIndex        @ index >= length, bail
+    @ May want to swap the order of these two branches depending on how the
+    @ branch prediction (if any) handles conditional forward branches vs.
+    @ unconditional forward branches.
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT_OBJECT: /* 0x4d */
+/* File: armv5te/OP_APUT_OBJECT.S */
+    /*
+     * Store an object into an array.  vBB[vCC] <- vAA.
+     *
+     * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+     * instructions.  We use a pair of FETCH_Bs instead.
+     */
+    /* op vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    GET_VREG(r1, r2)                    @ r1<- vBB (array object)
+    GET_VREG(r0, r3)                    @ r0<- vCC (requested index)
+    cmp     r1, #0                      @ null array object?
+    GET_VREG(r9, r9)                    @ r9<- vAA
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r1, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r10, r1, r0, lsl #2         @ r10<- arrayObj + index*width
+    cmp     r0, r3                      @ compare unsigned index, length
+    bcc     .LOP_APUT_OBJECT_finish          @ we're okay, continue on
+    b       common_errArrayIndex        @ index >= length, bail
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT_BOOLEAN: /* 0x4e */
+/* File: armv5te/OP_APUT_BOOLEAN.S */
+/* File: armv5te/OP_APUT.S */
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA.
+     *
+     * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+     * instructions.  We use a pair of FETCH_Bs instead.
+     *
+     * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+     */
+    /* op vAA, vBB, vCC */
+    FETCH_B(r2, 1, 0)                   @ r2<- BB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    FETCH_B(r3, 1, 1)                   @ r3<- CC
+    GET_VREG(r0, r2)                    @ r0<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     r0, #0                      @ null array object?
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r0, r0, r1, lsl #0     @ r0<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    bcs     common_errArrayIndex        @ index >= length, bail
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r2, r9)                    @ r2<- vAA
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    strb  r2, [r0, #offArrayObject_contents]  @ vBB[vCC]<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT_BYTE: /* 0x4f */
+/* File: armv5te/OP_APUT_BYTE.S */
+/* File: armv5te/OP_APUT.S */
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA.
+     *
+     * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+     * instructions.  We use a pair of FETCH_Bs instead.
+     *
+     * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+     */
+    /* op vAA, vBB, vCC */
+    FETCH_B(r2, 1, 0)                   @ r2<- BB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    FETCH_B(r3, 1, 1)                   @ r3<- CC
+    GET_VREG(r0, r2)                    @ r0<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     r0, #0                      @ null array object?
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r0, r0, r1, lsl #0     @ r0<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    bcs     common_errArrayIndex        @ index >= length, bail
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r2, r9)                    @ r2<- vAA
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    strb  r2, [r0, #offArrayObject_contents]  @ vBB[vCC]<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT_CHAR: /* 0x50 */
+/* File: armv5te/OP_APUT_CHAR.S */
+/* File: armv5te/OP_APUT.S */
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA.
+     *
+     * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+     * instructions.  We use a pair of FETCH_Bs instead.
+     *
+     * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+     */
+    /* op vAA, vBB, vCC */
+    FETCH_B(r2, 1, 0)                   @ r2<- BB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    FETCH_B(r3, 1, 1)                   @ r3<- CC
+    GET_VREG(r0, r2)                    @ r0<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     r0, #0                      @ null array object?
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r0, r0, r1, lsl #1     @ r0<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    bcs     common_errArrayIndex        @ index >= length, bail
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r2, r9)                    @ r2<- vAA
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    strh  r2, [r0, #offArrayObject_contents]  @ vBB[vCC]<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_APUT_SHORT: /* 0x51 */
+/* File: armv5te/OP_APUT_SHORT.S */
+/* File: armv5te/OP_APUT.S */
+    /*
+     * Array put, 32 bits or less.  vBB[vCC] <- vAA.
+     *
+     * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+     * instructions.  We use a pair of FETCH_Bs instead.
+     *
+     * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+     */
+    /* op vAA, vBB, vCC */
+    FETCH_B(r2, 1, 0)                   @ r2<- BB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    FETCH_B(r3, 1, 1)                   @ r3<- CC
+    GET_VREG(r0, r2)                    @ r0<- vBB (array object)
+    GET_VREG(r1, r3)                    @ r1<- vCC (requested index)
+    cmp     r0, #0                      @ null array object?
+    beq     common_errNullObject        @ yes, bail
+    ldr     r3, [r0, #offArrayObject_length]    @ r3<- arrayObj->length
+    add     r0, r0, r1, lsl #1     @ r0<- arrayObj + index*width
+    cmp     r1, r3                      @ compare unsigned index, length
+    bcs     common_errArrayIndex        @ index >= length, bail
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r2, r9)                    @ r2<- vAA
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    strh  r2, [r0, #offArrayObject_contents]  @ vBB[vCC]<- r2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET: /* 0x52 */
+/* File: armv6t2/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_finish
+    b       common_exceptionThrown
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE: /* 0x53 */
+/* File: armv6t2/OP_IGET_WIDE.S */
+    /*
+     * Wide 32-bit instance field get.
+     */
+    /* iget-wide vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_WIDE_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_WIDE_finish
+    b       common_exceptionThrown
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT: /* 0x54 */
+/* File: armv5te/OP_IGET_OBJECT.S */
+/* File: armv5te/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_OBJECT_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_OBJECT_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BOOLEAN: /* 0x55 */
+/* File: armv5te/OP_IGET_BOOLEAN.S */
+@include "armv5te/OP_IGET.S" { "load":"ldrb", "sqnum":"1" }
+/* File: armv5te/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_BOOLEAN_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_BOOLEAN_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_BYTE: /* 0x56 */
+/* File: armv5te/OP_IGET_BYTE.S */
+@include "armv5te/OP_IGET.S" { "load":"ldrsb", "sqnum":"2" }
+/* File: armv5te/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_BYTE_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_BYTE_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_CHAR: /* 0x57 */
+/* File: armv5te/OP_IGET_CHAR.S */
+@include "armv5te/OP_IGET.S" { "load":"ldrh", "sqnum":"3" }
+/* File: armv5te/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_CHAR_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_CHAR_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_SHORT: /* 0x58 */
+/* File: armv5te/OP_IGET_SHORT.S */
+@include "armv5te/OP_IGET.S" { "load":"ldrsh", "sqnum":"4" }
+/* File: armv5te/OP_IGET.S */
+    /*
+     * General 32-bit instance field get.
+     *
+     * for: iget, iget-object, iget-boolean, iget-byte, iget-char, iget-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IGET_SHORT_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0
+    bne     .LOP_IGET_SHORT_finish
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT: /* 0x59 */
+/* File: armv6t2/OP_IPUT.S */
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE: /* 0x5a */
+/* File: armv6t2/OP_IPUT_WIDE.S */
+    /* iput-wide vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_WIDE_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method] @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_WIDE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT: /* 0x5b */
+/* File: armv5te/OP_IPUT_OBJECT.S */
+/* File: armv5te/OP_IPUT.S */
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_OBJECT_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_OBJECT_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BOOLEAN: /* 0x5c */
+/* File: armv5te/OP_IPUT_BOOLEAN.S */
+@include "armv5te/OP_IPUT.S" { "store":"strb", "sqnum":"1" }
+/* File: armv5te/OP_IPUT.S */
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_BOOLEAN_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_BOOLEAN_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_BYTE: /* 0x5d */
+/* File: armv5te/OP_IPUT_BYTE.S */
+@include "armv5te/OP_IPUT.S" { "store":"strb", "sqnum":"2" }
+/* File: armv5te/OP_IPUT.S */
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_BYTE_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_BYTE_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_CHAR: /* 0x5e */
+/* File: armv5te/OP_IPUT_CHAR.S */
+@include "armv5te/OP_IPUT.S" { "store":"strh", "sqnum":"3" }
+/* File: armv5te/OP_IPUT.S */
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_CHAR_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_CHAR_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_SHORT: /* 0x5f */
+/* File: armv5te/OP_IPUT_SHORT.S */
+@include "armv5te/OP_IPUT.S" { "store":"strh", "sqnum":"4" }
+/* File: armv5te/OP_IPUT.S */
+    /*
+     * General 32-bit instance field put.
+     *
+     * for: iput, iput-object, iput-boolean, iput-byte, iput-char, iput-short
+     */
+    /* op vA, vB, field@CCCC */
+    mov     r0, rINST, lsr #12          @ r0<- B
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref CCCC
+    ldr     r2, [r3, #offDvmDex_pResFields] @ r2<- pDvmDex->pResFields
+    GET_VREG(r9, r0)                    @ r9<- fp[B], the object pointer
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    bne     .LOP_IPUT_SHORT_finish          @ no, already resolved
+8:  ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveInstField         @ r0<- resolved InstField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_IPUT_SHORT_finish          @ yes, finish up
+    b       common_exceptionThrown
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET: /* 0x60 */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_resolve         @ yes, do resolve
+.LOP_SGET_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_WIDE: /* 0x61 */
+/* File: armv5te/OP_SGET_WIDE.S */
+    /*
+     * 64-bit SGET handler.
+     */
+    /* sget-wide vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_WIDE_resolve         @ yes, do resolve
+.LOP_SGET_WIDE_finish:
+    mov     r1, rINST, lsr #8           @ r1<- AA
+    ldrd    r2, [r0, #offStaticField_value] @ r2/r3<- field value (aligned)
+    add     r1, rFP, r1, lsl #2         @ r1<- &fp[AA]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    stmia   r1, {r2-r3}                 @ vAA/vAA+1<- r2/r3
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_OBJECT: /* 0x62 */
+/* File: armv5te/OP_SGET_OBJECT.S */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_OBJECT_resolve         @ yes, do resolve
+.LOP_SGET_OBJECT_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BOOLEAN: /* 0x63 */
+/* File: armv5te/OP_SGET_BOOLEAN.S */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_BOOLEAN_resolve         @ yes, do resolve
+.LOP_SGET_BOOLEAN_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_BYTE: /* 0x64 */
+/* File: armv5te/OP_SGET_BYTE.S */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_BYTE_resolve         @ yes, do resolve
+.LOP_SGET_BYTE_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_CHAR: /* 0x65 */
+/* File: armv5te/OP_SGET_CHAR.S */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_CHAR_resolve         @ yes, do resolve
+.LOP_SGET_CHAR_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SGET_SHORT: /* 0x66 */
+/* File: armv5te/OP_SGET_SHORT.S */
+/* File: armv5te/OP_SGET.S */
+    /*
+     * General 32-bit SGET handler.
+     *
+     * for: sget, sget-object, sget-boolean, sget-byte, sget-char, sget-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SGET_SHORT_resolve         @ yes, do resolve
+.LOP_SGET_SHORT_finish: @ field ptr in r0
+    ldr     r1, [r0, #offStaticField_value] @ r1<- field value
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r2)                    @ fp[AA]<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT: /* 0x67 */
+/* File: armv5te/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_resolve         @ yes, do resolve
+.LOP_SPUT_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_WIDE: /* 0x68 */
+/* File: armv5te/OP_SPUT_WIDE.S */
+    /*
+     * 64-bit SPUT handler.
+     */
+    /* sput-wide vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_WIDE_resolve         @ yes, do resolve
+.LOP_SPUT_WIDE_finish: @ field ptr in r0, AA in r9
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r9, {r2-r3}                 @ r2/r3<- vAA/vAA+1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    strd    r2, [r0, #offStaticField_value] @ field<- vAA/vAA+1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_OBJECT: /* 0x69 */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+/* File: armv5te/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_OBJECT_resolve         @ yes, do resolve
+.LOP_SPUT_OBJECT_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BOOLEAN: /* 0x6a */
+/* File: armv5te/OP_SPUT_BOOLEAN.S */
+/* File: armv5te/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_BOOLEAN_resolve         @ yes, do resolve
+.LOP_SPUT_BOOLEAN_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_BYTE: /* 0x6b */
+/* File: armv5te/OP_SPUT_BYTE.S */
+/* File: armv5te/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_BYTE_resolve         @ yes, do resolve
+.LOP_SPUT_BYTE_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_CHAR: /* 0x6c */
+/* File: armv5te/OP_SPUT_CHAR.S */
+/* File: armv5te/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_CHAR_resolve         @ yes, do resolve
+.LOP_SPUT_CHAR_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SPUT_SHORT: /* 0x6d */
+/* File: armv5te/OP_SPUT_SHORT.S */
+/* File: armv5te/OP_SPUT.S */
+    /*
+     * General 32-bit SPUT handler.
+     *
+     * for: sput, sput-object, sput-boolean, sput-byte, sput-char, sput-short
+     */
+    /* op vAA, field@BBBB */
+    ldr     r2, [rGLUE, #offGlue_methodClassDex]    @ r2<- DvmDex
+    FETCH(r1, 1)                        @ r1<- field ref BBBB
+    ldr     r2, [r2, #offDvmDex_pResFields] @ r2<- dvmDex->pResFields
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ is resolved entry null?
+    beq     .LOP_SPUT_SHORT_resolve         @ yes, do resolve
+.LOP_SPUT_SHORT_finish:   @ field ptr in r0
+    mov     r2, rINST, lsr #8           @ r2<- AA
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_VREG(r1, r2)                    @ r1<- fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r1, [r0, #offStaticField_value] @ field<- vAA
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_VIRTUAL: /* 0x6e */
+/* File: armv5te/OP_INVOKE_VIRTUAL.S */
+    /*
+     * Handle a virtual method call.
+     *
+     * for: invoke-virtual, invoke-virtual/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    FETCH(r10, 2)                       @ r10<- GFED or CCCC
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    .if     (!0)
+    and     r10, r10, #15               @ r10<- D (or stays CCCC)
+    .endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     .LOP_INVOKE_VIRTUAL_continue        @ yes, continue on
+    ldr     r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+    ldr     r0, [r3, #offMethod_clazz]  @ r0<- method->clazz
+    mov     r2, #METHOD_VIRTUAL         @ resolver method type
+    bl      dvmResolveMethod            @ r0<- call(clazz, ref, flags)
+    cmp     r0, #0                      @ got null?
+    bne     .LOP_INVOKE_VIRTUAL_continue        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_SUPER: /* 0x6f */
+/* File: armv5te/OP_INVOKE_SUPER.S */
+    /*
+     * Handle a "super" method call.
+     *
+     * for: invoke-super, invoke-super/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    FETCH(r10, 2)                       @ r10<- GFED or CCCC
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- pDvmDex
+    .if     (!0)
+    and     r10, r10, #15               @ r10<- D (or stays CCCC)
+    .endif
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    GET_VREG(r2, r10)                   @ r2<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r2, #0                      @ null "this"?
+    ldr     r9, [rGLUE, #offGlue_method] @ r9<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r9, [r9, #offMethod_clazz]  @ r9<- method->clazz
+    EXPORT_PC()                         @ must export for invoke
+    bne     .LOP_INVOKE_SUPER_continue        @ resolved, continue on
+    b       .LOP_INVOKE_SUPER_resolve         @ do resolve now
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_DIRECT: /* 0x70 */
+/* File: armv5te/OP_INVOKE_DIRECT.S */
+    /*
+     * Handle a direct method call.
+     *
+     * (We could defer the "is 'this' pointer null" test to the common
+     * method invocation code, and use a flag to indicate that static
+     * calls don't count.  If we do this as part of copying the arguments
+     * out we could avoiding loading the first arg twice.)
+     *
+     * for: invoke-direct, invoke-direct/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    FETCH(r10, 2)                       @ r10<- GFED or CCCC
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+    .if     (!0)
+    and     r10, r10, #15               @ r10<- D (or stays CCCC)
+    .endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    GET_VREG(r2, r10)                   @ r2<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_finish:
+    cmp     r2, #0                      @ null "this" ref?
+    bne     common_invokeMethodNoRange   @ no, continue on
+    b       common_errNullObject        @ yes, throw exception
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_STATIC: /* 0x71 */
+/* File: armv5te/OP_INVOKE_STATIC.S */
+    /*
+     * Handle a static method call.
+     *
+     * for: invoke-static, invoke-static/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodNoRange @ yes, continue on
+0:  ldr     r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+    ldr     r0, [r3, #offMethod_clazz]  @ r0<- method->clazz
+    mov     r2, #METHOD_STATIC          @ resolver method type
+    bl      dvmResolveMethod            @ r0<- call(clazz, ref, flags)
+    cmp     r0, #0                      @ got null?
+    bne     common_invokeMethodNoRange @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_INTERFACE: /* 0x72 */
+/* File: armv5te/OP_INVOKE_INTERFACE.S */
+    /*
+     * Handle an interface method call.
+     *
+     * for: invoke-interface, invoke-interface/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    FETCH(r2, 2)                        @ r2<- FEDC or CCCC
+    FETCH(r1, 1)                        @ r1<- BBBB
+    .if     (!0)
+    and     r2, r2, #15                 @ r2<- C (or stays CCCC)
+    .endif
+    EXPORT_PC()                         @ must export for invoke
+    GET_VREG(r0, r2)                    @ r0<- first arg ("this")
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- methodClassDex
+    cmp     r0, #0                      @ null obj?
+    ldr     r2, [rGLUE, #offGlue_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r0, #offObject_clazz]  @ r0<- thisPtr->clazz
+    bl      dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
+    cmp     r0, #0                      @ failed?
+    beq     common_exceptionThrown      @ yes, handle exception
+    b       common_invokeMethodNoRange @ jump to common handler 
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_73: /* 0x73 */
+/* File: armv5te/OP_UNUSED_73.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
+/* File: armv5te/OP_INVOKE_VIRTUAL_RANGE.S */
+/* File: armv5te/OP_INVOKE_VIRTUAL.S */
+    /*
+     * Handle a virtual method call.
+     *
+     * for: invoke-virtual, invoke-virtual/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    FETCH(r10, 2)                       @ r10<- GFED or CCCC
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    .if     (!1)
+    and     r10, r10, #15               @ r10<- D (or stays CCCC)
+    .endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     .LOP_INVOKE_VIRTUAL_RANGE_continue        @ yes, continue on
+    ldr     r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+    ldr     r0, [r3, #offMethod_clazz]  @ r0<- method->clazz
+    mov     r2, #METHOD_VIRTUAL         @ resolver method type
+    bl      dvmResolveMethod            @ r0<- call(clazz, ref, flags)
+    cmp     r0, #0                      @ got null?
+    bne     .LOP_INVOKE_VIRTUAL_RANGE_continue        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_SUPER_RANGE: /* 0x75 */
+/* File: armv5te/OP_INVOKE_SUPER_RANGE.S */
+/* File: armv5te/OP_INVOKE_SUPER.S */
+    /*
+     * Handle a "super" method call.
+     *
+     * for: invoke-super, invoke-super/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    FETCH(r10, 2)                       @ r10<- GFED or CCCC
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- pDvmDex
+    .if     (!1)
+    and     r10, r10, #15               @ r10<- D (or stays CCCC)
+    .endif
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    GET_VREG(r2, r10)                   @ r2<- "this" ptr
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved baseMethod
+    cmp     r2, #0                      @ null "this"?
+    ldr     r9, [rGLUE, #offGlue_method] @ r9<- current method
+    beq     common_errNullObject        @ null "this", throw exception
+    cmp     r0, #0                      @ already resolved?
+    ldr     r9, [r9, #offMethod_clazz]  @ r9<- method->clazz
+    EXPORT_PC()                         @ must export for invoke
+    bne     .LOP_INVOKE_SUPER_RANGE_continue        @ resolved, continue on
+    b       .LOP_INVOKE_SUPER_RANGE_resolve         @ do resolve now
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
+/* File: armv5te/OP_INVOKE_DIRECT_RANGE.S */
+/* File: armv5te/OP_INVOKE_DIRECT.S */
+    /*
+     * Handle a direct method call.
+     *
+     * (We could defer the "is 'this' pointer null" test to the common
+     * method invocation code, and use a flag to indicate that static
+     * calls don't count.  If we do this as part of copying the arguments
+     * out we could avoiding loading the first arg twice.)
+     *
+     * for: invoke-direct, invoke-direct/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    FETCH(r10, 2)                       @ r10<- GFED or CCCC
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+    .if     (!1)
+    and     r10, r10, #15               @ r10<- D (or stays CCCC)
+    .endif
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    GET_VREG(r2, r10)                   @ r2<- "this" ptr
+    beq     .LOP_INVOKE_DIRECT_RANGE_resolve         @ not resolved, do it now
+.LOP_INVOKE_DIRECT_RANGE_finish:
+    cmp     r2, #0                      @ null "this" ref?
+    bne     common_invokeMethodRange   @ no, continue on
+    b       common_errNullObject        @ yes, throw exception
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_STATIC_RANGE: /* 0x77 */
+/* File: armv5te/OP_INVOKE_STATIC_RANGE.S */
+/* File: armv5te/OP_INVOKE_STATIC.S */
+    /*
+     * Handle a static method call.
+     *
+     * for: invoke-static, invoke-static/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- pDvmDex
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r3, [r3, #offDvmDex_pResMethods]    @ r3<- pDvmDex->pResMethods
+    ldr     r0, [r3, r1, lsl #2]        @ r0<- resolved methodToCall
+    cmp     r0, #0                      @ already resolved?
+    EXPORT_PC()                         @ must export for invoke
+    bne     common_invokeMethodRange @ yes, continue on
+0:  ldr     r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+    ldr     r0, [r3, #offMethod_clazz]  @ r0<- method->clazz
+    mov     r2, #METHOD_STATIC          @ resolver method type
+    bl      dvmResolveMethod            @ r0<- call(clazz, ref, flags)
+    cmp     r0, #0                      @ got null?
+    bne     common_invokeMethodRange @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
+/* File: armv5te/OP_INVOKE_INTERFACE_RANGE.S */
+/* File: armv5te/OP_INVOKE_INTERFACE.S */
+    /*
+     * Handle an interface method call.
+     *
+     * for: invoke-interface, invoke-interface/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    FETCH(r2, 2)                        @ r2<- FEDC or CCCC
+    FETCH(r1, 1)                        @ r1<- BBBB
+    .if     (!1)
+    and     r2, r2, #15                 @ r2<- C (or stays CCCC)
+    .endif
+    EXPORT_PC()                         @ must export for invoke
+    GET_VREG(r0, r2)                    @ r0<- first arg ("this")
+    ldr     r3, [rGLUE, #offGlue_methodClassDex]    @ r3<- methodClassDex
+    cmp     r0, #0                      @ null obj?
+    ldr     r2, [rGLUE, #offGlue_method]  @ r2<- method
+    beq     common_errNullObject        @ yes, fail
+    ldr     r0, [r0, #offObject_clazz]  @ r0<- thisPtr->clazz
+    bl      dvmFindInterfaceMethodInCache @ r0<- call(class, ref, method, dex)
+    cmp     r0, #0                      @ failed?
+    beq     common_exceptionThrown      @ yes, handle exception
+    b       common_invokeMethodRange @ jump to common handler 
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_79: /* 0x79 */
+/* File: armv5te/OP_UNUSED_79.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_7A: /* 0x7a */
+/* File: armv5te/OP_UNUSED_7A.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEG_INT: /* 0x7b */
+/* File: armv6t2/OP_NEG_INT.S */
+/* File: armv6t2/unop.S */
+    /*
+     * Generic 32-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op r0".
+     * This could be an ARM instruction or a function call.
+     *
+     * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+     *      int-to-byte, int-to-char, int-to-short
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r3)                    @ r0<- vB
+                               @ optional op; may set condition codes
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    rsb     r0, r0, #0                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 8-9 instructions */
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NOT_INT: /* 0x7c */
+/* File: armv6t2/OP_NOT_INT.S */
+/* File: armv6t2/unop.S */
+    /*
+     * Generic 32-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op r0".
+     * This could be an ARM instruction or a function call.
+     *
+     * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+     *      int-to-byte, int-to-char, int-to-short
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r3)                    @ r0<- vB
+                               @ optional op; may set condition codes
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    mvn     r0, r0                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 8-9 instructions */
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEG_LONG: /* 0x7d */
+/* File: armv6t2/OP_NEG_LONG.S */
+/* File: armv6t2/unopWide.S */
+    /*
+     * Generic 64-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op r0/r1".
+     * This could be an ARM instruction or a function call.
+     *
+     * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    ldmia   r3, {r0-r1}                 @ r0/r1<- vAA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    rsbs    r0, r0, #0                           @ optional op; may set condition codes
+    rsc     r1, r1, #0                              @ r0/r1<- op, r2-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vAA<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-11 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NOT_LONG: /* 0x7e */
+/* File: armv6t2/OP_NOT_LONG.S */
+/* File: armv6t2/unopWide.S */
+    /*
+     * Generic 64-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op r0/r1".
+     * This could be an ARM instruction or a function call.
+     *
+     * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    ldmia   r3, {r0-r1}                 @ r0/r1<- vAA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    mvn     r0, r0                           @ optional op; may set condition codes
+    mvn     r1, r1                              @ r0/r1<- op, r2-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vAA<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-11 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEG_FLOAT: /* 0x7f */
+/* File: armv6t2/OP_NEG_FLOAT.S */
+/* File: armv6t2/unop.S */
+    /*
+     * Generic 32-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op r0".
+     * This could be an ARM instruction or a function call.
+     *
+     * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+     *      int-to-byte, int-to-char, int-to-short
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r3)                    @ r0<- vB
+                               @ optional op; may set condition codes
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    add     r0, r0, #0x80000000                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 8-9 instructions */
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_NEG_DOUBLE: /* 0x80 */
+/* File: armv6t2/OP_NEG_DOUBLE.S */
+/* File: armv6t2/unopWide.S */
+    /*
+     * Generic 64-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op r0/r1".
+     * This could be an ARM instruction or a function call.
+     *
+     * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    ldmia   r3, {r0-r1}                 @ r0/r1<- vAA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+                               @ optional op; may set condition codes
+    add     r1, r1, #0x80000000                              @ r0/r1<- op, r2-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vAA<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-11 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INT_TO_LONG: /* 0x81 */
+/* File: armv6t2/OP_INT_TO_LONG.S */
+/* File: armv6t2/unopWider.S */
+    /*
+     * Generic 32bit-to-64bit unary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = op r0", where
+     * "result" is a 64-bit quantity in r0/r1.
+     *
+     * For: int-to-long, int-to-double, float-to-long, float-to-double
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r3)                    @ r0<- vB
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+                               @ optional op; may set condition codes
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    mov     r1, r0, asr #31                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vA/vA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 9-10 instructions */
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INT_TO_FLOAT: /* 0x82 */
+/* File: arm-vfp/OP_INT_TO_FLOAT.S */
+/* File: arm-vfp/funop.S */
+    /*
+     * Generic 32-bit unary floating-point operation.  Provide an "instr"
+     * line that specifies an instruction that performs "s1 = op s0".
+     *
+     * for: int-to-float, float-to-int
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    flds    s0, [r3]                    @ s0<- vB
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    and     r9, r9, #15                 @ r9<- A
+    fsitos  s1, s0                              @ s1<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    fsts    s1, [r9]                    @ vA<- s1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INT_TO_DOUBLE: /* 0x83 */
+/* File: arm-vfp/OP_INT_TO_DOUBLE.S */
+/* File: arm-vfp/funopWider.S */
+    /*
+     * Generic 32bit-to-64bit floating point unary operation.  Provide an
+     * "instr" line that specifies an instruction that performs "d0 = op s0".
+     *
+     * For: int-to-double, float-to-double
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    flds    s0, [r3]                    @ s0<- vB
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    and     r9, r9, #15                 @ r9<- A
+    fsitod  d0, s0                              @ d0<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    fstd    d0, [r9]                    @ vA<- d0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_LONG_TO_INT: /* 0x84 */
+/* File: armv5te/OP_LONG_TO_INT.S */
+/* we ignore the high word, making this equivalent to a 32-bit reg move */
+/* File: armv5te/OP_MOVE.S */
+    /* for move, move-object, long-to-int */
+    /* op vA, vB */
+    mov     r1, rINST, lsr #12          @ r1<- B from 15:12
+    mov     r0, rINST, lsr #8           @ r0<- A from 11:8
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    GET_VREG(r2, r1)                    @ r2<- fp[B]
+    and     r0, r0, #15
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    SET_VREG(r2, r0)                    @ fp[A]<- r2
+    GOTO_OPCODE(ip)                     @ execute next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_LONG_TO_FLOAT: /* 0x85 */
+/* File: armv6t2/OP_LONG_TO_FLOAT.S */
+/* File: armv6t2/unopNarrower.S */
+    /*
+     * Generic 64bit-to-32bit unary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = op r0/r1", where
+     * "result" is a 32-bit quantity in r0.
+     *
+     * For: long-to-float, double-to-int, double-to-float
+     *
+     * (This would work for long-to-int, but that instruction is actually
+     * an exact match for OP_MOVE.)
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
+    ldmia   r3, {r0-r1}                 @ r0/r1<- vB/vB+1
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+                               @ optional op; may set condition codes
+    bl      __aeabi_l2f                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 9-10 instructions */
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_LONG_TO_DOUBLE: /* 0x86 */
+/* File: armv6t2/OP_LONG_TO_DOUBLE.S */
+/* File: armv6t2/unopWide.S */
+    /*
+     * Generic 64-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op r0/r1".
+     * This could be an ARM instruction or a function call.
+     *
+     * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    ldmia   r3, {r0-r1}                 @ r0/r1<- vAA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+                               @ optional op; may set condition codes
+    bl      __aeabi_l2d                              @ r0/r1<- op, r2-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vAA<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-11 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FLOAT_TO_INT: /* 0x87 */
+/* File: arm-vfp/OP_FLOAT_TO_INT.S */
+/* File: arm-vfp/funop.S */
+    /*
+     * Generic 32-bit unary floating-point operation.  Provide an "instr"
+     * line that specifies an instruction that performs "s1 = op s0".
+     *
+     * for: int-to-float, float-to-int
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    flds    s0, [r3]                    @ s0<- vB
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    and     r9, r9, #15                 @ r9<- A
+    ftosizs s1, s0                              @ s1<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    fsts    s1, [r9]                    @ vA<- s1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FLOAT_TO_LONG: /* 0x88 */
+/* File: armv6t2/OP_FLOAT_TO_LONG.S */
+@include "armv6t2/unopWider.S" {"instr":"bl      __aeabi_f2lz"}
+/* File: armv6t2/unopWider.S */
+    /*
+     * Generic 32bit-to-64bit unary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = op r0", where
+     * "result" is a 64-bit quantity in r0/r1.
+     *
+     * For: int-to-long, int-to-double, float-to-long, float-to-double
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r3)                    @ r0<- vB
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+                               @ optional op; may set condition codes
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    bl      f2l_doconv                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vA/vA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 9-10 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_FLOAT_TO_DOUBLE: /* 0x89 */
+/* File: arm-vfp/OP_FLOAT_TO_DOUBLE.S */
+/* File: arm-vfp/funopWider.S */
+    /*
+     * Generic 32bit-to-64bit floating point unary operation.  Provide an
+     * "instr" line that specifies an instruction that performs "d0 = op s0".
+     *
+     * For: int-to-double, float-to-double
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    flds    s0, [r3]                    @ s0<- vB
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    and     r9, r9, #15                 @ r9<- A
+    fcvtds  d0, s0                              @ d0<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    fstd    d0, [r9]                    @ vA<- d0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DOUBLE_TO_INT: /* 0x8a */
+/* File: arm-vfp/OP_DOUBLE_TO_INT.S */
+/* File: arm-vfp/funopNarrower.S */
+    /*
+     * Generic 64bit-to-32bit unary floating point operation.  Provide an
+     * "instr" line that specifies an instruction that performs "s0 = op d0".
+     *
+     * For: double-to-int, double-to-float
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    fldd    d0, [r3]                    @ d0<- vB
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    and     r9, r9, #15                 @ r9<- A
+    ftosizd  s0, d0                              @ s0<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    fsts    s0, [r9]                    @ vA<- s0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DOUBLE_TO_LONG: /* 0x8b */
+/* File: armv6t2/OP_DOUBLE_TO_LONG.S */
+@include "armv6t2/unopWide.S" {"instr":"bl      __aeabi_d2lz"}
+/* File: armv6t2/unopWide.S */
+    /*
+     * Generic 64-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op r0/r1".
+     * This could be an ARM instruction or a function call.
+     *
+     * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    ldmia   r3, {r0-r1}                 @ r0/r1<- vAA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+                               @ optional op; may set condition codes
+    bl      d2l_doconv                              @ r0/r1<- op, r2-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vAA<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-11 instructions */
+
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DOUBLE_TO_FLOAT: /* 0x8c */
+/* File: arm-vfp/OP_DOUBLE_TO_FLOAT.S */
+/* File: arm-vfp/funopNarrower.S */
+    /*
+     * Generic 64bit-to-32bit unary floating point operation.  Provide an
+     * "instr" line that specifies an instruction that performs "s0 = op d0".
+     *
+     * For: double-to-int, double-to-float
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    fldd    d0, [r3]                    @ d0<- vB
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    and     r9, r9, #15                 @ r9<- A
+    fcvtsd  s0, d0                              @ s0<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    fsts    s0, [r9]                    @ vA<- s0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INT_TO_BYTE: /* 0x8d */
+/* File: armv6t2/OP_INT_TO_BYTE.S */
+/* File: armv6t2/unop.S */
+    /*
+     * Generic 32-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op r0".
+     * This could be an ARM instruction or a function call.
+     *
+     * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+     *      int-to-byte, int-to-char, int-to-short
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r3)                    @ r0<- vB
+                               @ optional op; may set condition codes
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    sxtb    r0, r0                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 8-9 instructions */
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INT_TO_CHAR: /* 0x8e */
+/* File: armv6t2/OP_INT_TO_CHAR.S */
+/* File: armv6t2/unop.S */
+    /*
+     * Generic 32-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op r0".
+     * This could be an ARM instruction or a function call.
+     *
+     * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+     *      int-to-byte, int-to-char, int-to-short
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r3)                    @ r0<- vB
+                               @ optional op; may set condition codes
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    uxth    r0, r0                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 8-9 instructions */
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INT_TO_SHORT: /* 0x8f */
+/* File: armv6t2/OP_INT_TO_SHORT.S */
+/* File: armv6t2/unop.S */
+    /*
+     * Generic 32-bit unary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = op r0".
+     * This could be an ARM instruction or a function call.
+     *
+     * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+     *      int-to-byte, int-to-char, int-to-short
+     */
+    /* unop vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r3)                    @ r0<- vB
+                               @ optional op; may set condition codes
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    sxth    r0, r0                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 8-9 instructions */
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_INT: /* 0x90 */
+/* File: armv5te/OP_ADD_INT.S */
+/* File: armv5te/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+     * handles it correctly.
+     *
+     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+     *      mul-float, div-float, rem-float
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    GET_VREG(r1, r3)                    @ r1<- vCC
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+                               @ optional op; may set condition codes
+    add     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_INT: /* 0x91 */
+/* File: armv5te/OP_SUB_INT.S */
+/* File: armv5te/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+     * handles it correctly.
+     *
+     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+     *      mul-float, div-float, rem-float
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    GET_VREG(r1, r3)                    @ r1<- vCC
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+                               @ optional op; may set condition codes
+    sub     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_INT: /* 0x92 */
+/* File: armv5te/OP_MUL_INT.S */
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+/* File: armv5te/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+     * handles it correctly.
+     *
+     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+     *      mul-float, div-float, rem-float
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    GET_VREG(r1, r3)                    @ r1<- vCC
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+                               @ optional op; may set condition codes
+    mul     r0, r1, r0                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_INT: /* 0x93 */
+/* File: armv5te/OP_DIV_INT.S */
+/* File: armv5te/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+     * handles it correctly.
+     *
+     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+     *      mul-float, div-float, rem-float
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    GET_VREG(r1, r3)                    @ r1<- vCC
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    .if 1
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+                               @ optional op; may set condition codes
+    bl     __aeabi_idiv                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_INT: /* 0x94 */
+/* File: armv5te/OP_REM_INT.S */
+/* idivmod returns quotient in r0 and remainder in r1 */
+/* File: armv5te/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+     * handles it correctly.
+     *
+     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+     *      mul-float, div-float, rem-float
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    GET_VREG(r1, r3)                    @ r1<- vCC
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    .if 1
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+                               @ optional op; may set condition codes
+    bl      __aeabi_idivmod                              @ r1<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r1, r9)               @ vAA<- r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AND_INT: /* 0x95 */
+/* File: armv5te/OP_AND_INT.S */
+/* File: armv5te/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+     * handles it correctly.
+     *
+     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+     *      mul-float, div-float, rem-float
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    GET_VREG(r1, r3)                    @ r1<- vCC
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+                               @ optional op; may set condition codes
+    and     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_OR_INT: /* 0x96 */
+/* File: armv5te/OP_OR_INT.S */
+/* File: armv5te/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+     * handles it correctly.
+     *
+     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+     *      mul-float, div-float, rem-float
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    GET_VREG(r1, r3)                    @ r1<- vCC
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+                               @ optional op; may set condition codes
+    orr     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_XOR_INT: /* 0x97 */
+/* File: armv5te/OP_XOR_INT.S */
+/* File: armv5te/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+     * handles it correctly.
+     *
+     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+     *      mul-float, div-float, rem-float
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    GET_VREG(r1, r3)                    @ r1<- vCC
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+                               @ optional op; may set condition codes
+    eor     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHL_INT: /* 0x98 */
+/* File: armv5te/OP_SHL_INT.S */
+/* File: armv5te/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+     * handles it correctly.
+     *
+     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+     *      mul-float, div-float, rem-float
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    GET_VREG(r1, r3)                    @ r1<- vCC
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r1, r1, #31                           @ optional op; may set condition codes
+    mov     r0, r0, asl r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHR_INT: /* 0x99 */
+/* File: armv5te/OP_SHR_INT.S */
+/* File: armv5te/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+     * handles it correctly.
+     *
+     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+     *      mul-float, div-float, rem-float
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    GET_VREG(r1, r3)                    @ r1<- vCC
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r1, r1, #31                           @ optional op; may set condition codes
+    mov     r0, r0, asr r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_USHR_INT: /* 0x9a */
+/* File: armv5te/OP_USHR_INT.S */
+/* File: armv5te/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+     * handles it correctly.
+     *
+     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+     *      mul-float, div-float, rem-float
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    GET_VREG(r1, r3)                    @ r1<- vCC
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r1, r1, #31                           @ optional op; may set condition codes
+    mov     r0, r0, lsr r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_LONG: /* 0x9b */
+/* File: armv5te/OP_ADD_LONG.S */
+/* File: armv5te/binopWide.S */
+    /*
+     * Generic 64-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+     *      xor-long, add-double, sub-double, mul-double, div-double,
+     *      rem-double
+     *
+     * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
+    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    .if 0
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    adds    r0, r0, r2                           @ optional op; may set condition codes
+    adc     r1, r1, r3                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_LONG: /* 0x9c */
+/* File: armv5te/OP_SUB_LONG.S */
+/* File: armv5te/binopWide.S */
+    /*
+     * Generic 64-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+     *      xor-long, add-double, sub-double, mul-double, div-double,
+     *      rem-double
+     *
+     * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
+    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    .if 0
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    subs    r0, r0, r2                           @ optional op; may set condition codes
+    sbc     r1, r1, r3                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_LONG: /* 0x9d */
+/* File: armv5te/OP_MUL_LONG.S */
+    /*
+     * Signed 64-bit integer multiply.
+     *
+     * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
+     *        WX
+     *      x YZ
+     *  --------
+     *     ZW ZX
+     *  YW YX
+     *
+     * The low word of the result holds ZX, the high word holds
+     * (ZW+YX) + (the high overflow from ZX).  YW doesn't matter because
+     * it doesn't fit in the low 64 bits.
+     *
+     * Unlike most ARM math operations, multiply instructions have
+     * restrictions on using the same register more than once (Rd and Rm
+     * cannot be the same).
+     */
+    /* mul-long vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
+    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    mul     ip, r2, r1                  @  ip<- ZxW
+    umull   r9, r10, r2, r0             @  r9/r10 <- ZxX
+    mla     r2, r0, r3, ip              @  r2<- YxX + (ZxW)
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    add     r10, r2, r10                @  r10<- r10 + low(ZxW + (YxX))
+    add     r0, rFP, r0, lsl #2         @ r0<- &fp[AA]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    b       .LOP_MUL_LONG_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_LONG: /* 0x9e */
+/* File: armv5te/OP_DIV_LONG.S */
+/* File: armv5te/binopWide.S */
+    /*
+     * Generic 64-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+     *      xor-long, add-double, sub-double, mul-double, div-double,
+     *      rem-double
+     *
+     * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
+    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    .if 1
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_ldivmod                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_LONG: /* 0x9f */
+/* File: armv5te/OP_REM_LONG.S */
+/* ldivmod returns quotient in r0/r1 and remainder in r2/r3 */
+/* File: armv5te/binopWide.S */
+    /*
+     * Generic 64-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+     *      xor-long, add-double, sub-double, mul-double, div-double,
+     *      rem-double
+     *
+     * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
+    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    .if 1
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_ldivmod                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r2,r3}     @ vAA/vAA+1<- r2/r3
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AND_LONG: /* 0xa0 */
+/* File: armv5te/OP_AND_LONG.S */
+/* File: armv5te/binopWide.S */
+    /*
+     * Generic 64-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+     *      xor-long, add-double, sub-double, mul-double, div-double,
+     *      rem-double
+     *
+     * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
+    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    .if 0
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    and     r0, r0, r2                           @ optional op; may set condition codes
+    and     r1, r1, r3                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_OR_LONG: /* 0xa1 */
+/* File: armv5te/OP_OR_LONG.S */
+/* File: armv5te/binopWide.S */
+    /*
+     * Generic 64-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+     *      xor-long, add-double, sub-double, mul-double, div-double,
+     *      rem-double
+     *
+     * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
+    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    .if 0
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    orr     r0, r0, r2                           @ optional op; may set condition codes
+    orr     r1, r1, r3                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_XOR_LONG: /* 0xa2 */
+/* File: armv5te/OP_XOR_LONG.S */
+/* File: armv5te/binopWide.S */
+    /*
+     * Generic 64-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+     *      xor-long, add-double, sub-double, mul-double, div-double,
+     *      rem-double
+     *
+     * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
+    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    .if 0
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    eor     r0, r0, r2                           @ optional op; may set condition codes
+    eor     r1, r1, r3                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHL_LONG: /* 0xa3 */
+/* File: armv5te/OP_SHL_LONG.S */
+    /*
+     * Long integer shift.  This is different from the generic 32/64-bit
+     * binary operations because vAA/vBB are 64-bit but vCC (the shift
+     * distance) is 32-bit.  Also, Dalvik requires us to mask off the low
+     * 6 bits of the shift distance.
+     */
+    /* shl-long vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r3, r0, #255                @ r3<- BB
+    mov     r0, r0, lsr #8              @ r0<- CC
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[BB]
+    GET_VREG(r2, r0)                    @ r2<- vCC
+    ldmia   r3, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    and     r2, r2, #63                 @ r2<- r2 & 0x3f
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+
+    mov     r1, r1, asl r2              @  r1<- r1 << r2
+    rsb     r3, r2, #32                 @  r3<- 32 - r2
+    orr     r1, r1, r0, lsr r3          @  r1<- r1 | (r0 << (32-r2))
+    subs    ip, r2, #32                 @  ip<- r2 - 32
+    movpl   r1, r0, asl ip              @  if r2 >= 32, r1<- r0 << (r2-32)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    b       .LOP_SHL_LONG_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHR_LONG: /* 0xa4 */
+/* File: armv5te/OP_SHR_LONG.S */
+    /*
+     * Long integer shift.  This is different from the generic 32/64-bit
+     * binary operations because vAA/vBB are 64-bit but vCC (the shift
+     * distance) is 32-bit.  Also, Dalvik requires us to mask off the low
+     * 6 bits of the shift distance.
+     */
+    /* shr-long vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r3, r0, #255                @ r3<- BB
+    mov     r0, r0, lsr #8              @ r0<- CC
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[BB]
+    GET_VREG(r2, r0)                    @ r2<- vCC
+    ldmia   r3, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    and     r2, r2, #63                 @ r0<- r0 & 0x3f
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+
+    mov     r0, r0, lsr r2              @  r0<- r2 >> r2
+    rsb     r3, r2, #32                 @  r3<- 32 - r2
+    orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
+    subs    ip, r2, #32                 @  ip<- r2 - 32
+    movpl   r0, r1, asr ip              @  if r2 >= 32, r0<-r1 >> (r2-32)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    b       .LOP_SHR_LONG_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_USHR_LONG: /* 0xa5 */
+/* File: armv5te/OP_USHR_LONG.S */
+    /*
+     * Long integer shift.  This is different from the generic 32/64-bit
+     * binary operations because vAA/vBB are 64-bit but vCC (the shift
+     * distance) is 32-bit.  Also, Dalvik requires us to mask off the low
+     * 6 bits of the shift distance.
+     */
+    /* ushr-long vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r3, r0, #255                @ r3<- BB
+    mov     r0, r0, lsr #8              @ r0<- CC
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[BB]
+    GET_VREG(r2, r0)                    @ r2<- vCC
+    ldmia   r3, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    and     r2, r2, #63                 @ r0<- r0 & 0x3f
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+
+    mov     r0, r0, lsr r2              @  r0<- r2 >> r2
+    rsb     r3, r2, #32                 @  r3<- 32 - r2
+    orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
+    subs    ip, r2, #32                 @  ip<- r2 - 32
+    movpl   r0, r1, lsr ip              @  if r2 >= 32, r0<-r1 >>> (r2-32)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    b       .LOP_USHR_LONG_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_FLOAT: /* 0xa6 */
+/* File: arm-vfp/OP_ADD_FLOAT.S */
+/* File: arm-vfp/fbinop.S */
+    /*
+     * Generic 32-bit floating-point operation.  Provide an "instr" line that
+     * specifies an instruction that performs "s2 = s0 op s1".  Because we
+     * use the "softfp" ABI, this must be an instruction, not a function call.
+     *
+     * For: add-float, sub-float, mul-float, div-float
+     */
+    /* floatop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vCC
+    VREG_INDEX_TO_ADDR(r2, r2)          @ r2<- &vBB
+    flds    s1, [r3]                    @ s1<- vCC
+    flds    s0, [r2]                    @ s0<- vBB
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    fadds   s2, s0, s1                              @ s2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vAA
+    fsts    s2, [r9]                    @ vAA<- s2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_FLOAT: /* 0xa7 */
+/* File: arm-vfp/OP_SUB_FLOAT.S */
+/* File: arm-vfp/fbinop.S */
+    /*
+     * Generic 32-bit floating-point operation.  Provide an "instr" line that
+     * specifies an instruction that performs "s2 = s0 op s1".  Because we
+     * use the "softfp" ABI, this must be an instruction, not a function call.
+     *
+     * For: add-float, sub-float, mul-float, div-float
+     */
+    /* floatop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vCC
+    VREG_INDEX_TO_ADDR(r2, r2)          @ r2<- &vBB
+    flds    s1, [r3]                    @ s1<- vCC
+    flds    s0, [r2]                    @ s0<- vBB
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    fsubs   s2, s0, s1                              @ s2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vAA
+    fsts    s2, [r9]                    @ vAA<- s2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_FLOAT: /* 0xa8 */
+/* File: arm-vfp/OP_MUL_FLOAT.S */
+/* File: arm-vfp/fbinop.S */
+    /*
+     * Generic 32-bit floating-point operation.  Provide an "instr" line that
+     * specifies an instruction that performs "s2 = s0 op s1".  Because we
+     * use the "softfp" ABI, this must be an instruction, not a function call.
+     *
+     * For: add-float, sub-float, mul-float, div-float
+     */
+    /* floatop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vCC
+    VREG_INDEX_TO_ADDR(r2, r2)          @ r2<- &vBB
+    flds    s1, [r3]                    @ s1<- vCC
+    flds    s0, [r2]                    @ s0<- vBB
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    fmuls   s2, s0, s1                              @ s2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vAA
+    fsts    s2, [r9]                    @ vAA<- s2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_FLOAT: /* 0xa9 */
+/* File: arm-vfp/OP_DIV_FLOAT.S */
+/* File: arm-vfp/fbinop.S */
+    /*
+     * Generic 32-bit floating-point operation.  Provide an "instr" line that
+     * specifies an instruction that performs "s2 = s0 op s1".  Because we
+     * use the "softfp" ABI, this must be an instruction, not a function call.
+     *
+     * For: add-float, sub-float, mul-float, div-float
+     */
+    /* floatop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vCC
+    VREG_INDEX_TO_ADDR(r2, r2)          @ r2<- &vBB
+    flds    s1, [r3]                    @ s1<- vCC
+    flds    s0, [r2]                    @ s0<- vBB
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    fdivs   s2, s0, s1                              @ s2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vAA
+    fsts    s2, [r9]                    @ vAA<- s2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_FLOAT: /* 0xaa */
+/* File: armv5te/OP_REM_FLOAT.S */
+/* EABI doesn't define a float remainder function, but libm does */
+/* File: armv5te/binop.S */
+    /*
+     * Generic 32-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.  Note that we
+     * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+     * handles it correctly.
+     *
+     * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+     *      xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+     *      mul-float, div-float, rem-float
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    GET_VREG(r1, r3)                    @ r1<- vCC
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+                               @ optional op; may set condition codes
+    bl      fmodf                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_DOUBLE: /* 0xab */
+/* File: arm-vfp/OP_ADD_DOUBLE.S */
+/* File: arm-vfp/fbinopWide.S */
+    /*
+     * Generic 64-bit double-precision floating point binary operation.
+     * Provide an "instr" line that specifies an instruction that performs
+     * "d2 = d0 op d1".
+     *
+     * for: add-double, sub-double, mul-double, div-double
+     */
+    /* doubleop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vCC
+    VREG_INDEX_TO_ADDR(r2, r2)          @ r2<- &vBB
+    fldd    d1, [r3]                    @ d1<- vCC
+    fldd    d0, [r2]                    @ d0<- vBB
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    faddd   d2, d0, d1                              @ s2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vAA
+    fstd    d2, [r9]                    @ vAA<- d2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_DOUBLE: /* 0xac */
+/* File: arm-vfp/OP_SUB_DOUBLE.S */
+/* File: arm-vfp/fbinopWide.S */
+    /*
+     * Generic 64-bit double-precision floating point binary operation.
+     * Provide an "instr" line that specifies an instruction that performs
+     * "d2 = d0 op d1".
+     *
+     * for: add-double, sub-double, mul-double, div-double
+     */
+    /* doubleop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vCC
+    VREG_INDEX_TO_ADDR(r2, r2)          @ r2<- &vBB
+    fldd    d1, [r3]                    @ d1<- vCC
+    fldd    d0, [r2]                    @ d0<- vBB
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    fsubd   d2, d0, d1                              @ s2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vAA
+    fstd    d2, [r9]                    @ vAA<- d2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_DOUBLE: /* 0xad */
+/* File: arm-vfp/OP_MUL_DOUBLE.S */
+/* File: arm-vfp/fbinopWide.S */
+    /*
+     * Generic 64-bit double-precision floating point binary operation.
+     * Provide an "instr" line that specifies an instruction that performs
+     * "d2 = d0 op d1".
+     *
+     * for: add-double, sub-double, mul-double, div-double
+     */
+    /* doubleop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vCC
+    VREG_INDEX_TO_ADDR(r2, r2)          @ r2<- &vBB
+    fldd    d1, [r3]                    @ d1<- vCC
+    fldd    d0, [r2]                    @ d0<- vBB
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    fmuld   d2, d0, d1                              @ s2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vAA
+    fstd    d2, [r9]                    @ vAA<- d2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_DOUBLE: /* 0xae */
+/* File: arm-vfp/OP_DIV_DOUBLE.S */
+/* File: arm-vfp/fbinopWide.S */
+    /*
+     * Generic 64-bit double-precision floating point binary operation.
+     * Provide an "instr" line that specifies an instruction that performs
+     * "d2 = d0 op d1".
+     *
+     * for: add-double, sub-double, mul-double, div-double
+     */
+    /* doubleop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     r3, r0, lsr #8              @ r3<- CC
+    and     r2, r0, #255                @ r2<- BB
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vCC
+    VREG_INDEX_TO_ADDR(r2, r2)          @ r2<- &vBB
+    fldd    d1, [r3]                    @ d1<- vCC
+    fldd    d0, [r2]                    @ d0<- vBB
+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    fdivd   d2, d0, d1                              @ s2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vAA
+    fstd    d2, [r9]                    @ vAA<- d2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_DOUBLE: /* 0xaf */
+/* File: armv5te/OP_REM_DOUBLE.S */
+/* EABI doesn't define a double remainder function, but libm does */
+/* File: armv5te/binopWide.S */
+    /*
+     * Generic 64-bit binary operation.  Provide an "instr" line that
+     * specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+     *      xor-long, add-double, sub-double, mul-double, div-double,
+     *      rem-double
+     *
+     * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+     */
+    /* binop vAA, vBB, vCC */
+    FETCH(r0, 1)                        @ r0<- CCBB
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r0, #255                @ r2<- BB
+    mov     r3, r0, lsr #8              @ r3<- CC
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
+    add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
+    ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
+    ldmia   r3, {r2-r3}                 @ r2/r3<- vCC/vCC+1
+    .if 0
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    bl      fmod                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_INT_2ADDR: /* 0xb0 */
+/* File: armv6t2/OP_ADD_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+    /*
+     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+     *      sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r1, r3)                    @ r1<- vB
+    GET_VREG(r0, r9)                    @ r0<- vA
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    add     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_INT_2ADDR: /* 0xb1 */
+/* File: armv6t2/OP_SUB_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+    /*
+     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+     *      sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r1, r3)                    @ r1<- vB
+    GET_VREG(r0, r9)                    @ r0<- vA
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    sub     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_INT_2ADDR: /* 0xb2 */
+/* File: armv6t2/OP_MUL_INT_2ADDR.S */
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+/* File: armv6t2/binop2addr.S */
+    /*
+     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+     *      sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r1, r3)                    @ r1<- vB
+    GET_VREG(r0, r9)                    @ r0<- vA
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    mul     r0, r1, r0                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_INT_2ADDR: /* 0xb3 */
+/* File: armv6t2/OP_DIV_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+    /*
+     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+     *      sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r1, r3)                    @ r1<- vB
+    GET_VREG(r0, r9)                    @ r0<- vA
+    .if 1
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    bl     __aeabi_idiv                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_INT_2ADDR: /* 0xb4 */
+/* File: armv6t2/OP_REM_INT_2ADDR.S */
+/* idivmod returns quotient in r0 and remainder in r1 */
+/* File: armv6t2/binop2addr.S */
+    /*
+     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+     *      sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r1, r3)                    @ r1<- vB
+    GET_VREG(r0, r9)                    @ r0<- vA
+    .if 1
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_idivmod                              @ r1<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r1, r9)               @ vAA<- r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AND_INT_2ADDR: /* 0xb5 */
+/* File: armv6t2/OP_AND_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+    /*
+     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+     *      sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r1, r3)                    @ r1<- vB
+    GET_VREG(r0, r9)                    @ r0<- vA
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    and     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_OR_INT_2ADDR: /* 0xb6 */
+/* File: armv6t2/OP_OR_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+    /*
+     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+     *      sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r1, r3)                    @ r1<- vB
+    GET_VREG(r0, r9)                    @ r0<- vA
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    orr     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_XOR_INT_2ADDR: /* 0xb7 */
+/* File: armv6t2/OP_XOR_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+    /*
+     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+     *      sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r1, r3)                    @ r1<- vB
+    GET_VREG(r0, r9)                    @ r0<- vA
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    eor     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHL_INT_2ADDR: /* 0xb8 */
+/* File: armv6t2/OP_SHL_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+    /*
+     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+     *      sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r1, r3)                    @ r1<- vB
+    GET_VREG(r0, r9)                    @ r0<- vA
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+    and     r1, r1, #31                           @ optional op; may set condition codes
+    mov     r0, r0, asl r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHR_INT_2ADDR: /* 0xb9 */
+/* File: armv6t2/OP_SHR_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+    /*
+     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+     *      sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r1, r3)                    @ r1<- vB
+    GET_VREG(r0, r9)                    @ r0<- vA
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+    and     r1, r1, #31                           @ optional op; may set condition codes
+    mov     r0, r0, asr r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_USHR_INT_2ADDR: /* 0xba */
+/* File: armv6t2/OP_USHR_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+    /*
+     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+     *      sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r1, r3)                    @ r1<- vB
+    GET_VREG(r0, r9)                    @ r0<- vA
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+    and     r1, r1, #31                           @ optional op; may set condition codes
+    mov     r0, r0, lsr r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_LONG_2ADDR: /* 0xbb */
+/* File: armv6t2/OP_ADD_LONG_2ADDR.S */
+/* File: armv6t2/binopWide2addr.S */
+    /*
+     * Generic 64-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+     *      and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+     *      sub-double/2addr, mul-double/2addr, div-double/2addr,
+     *      rem-double/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    .if 0
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+    adds    r0, r0, r2                           @ optional op; may set condition codes
+    adc     r1, r1, r3                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_LONG_2ADDR: /* 0xbc */
+/* File: armv6t2/OP_SUB_LONG_2ADDR.S */
+/* File: armv6t2/binopWide2addr.S */
+    /*
+     * Generic 64-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+     *      and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+     *      sub-double/2addr, mul-double/2addr, div-double/2addr,
+     *      rem-double/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    .if 0
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+    subs    r0, r0, r2                           @ optional op; may set condition codes
+    sbc     r1, r1, r3                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_LONG_2ADDR: /* 0xbd */
+/* File: armv6t2/OP_MUL_LONG_2ADDR.S */
+    /*
+     * Signed 64-bit integer multiply, "/2addr" version.
+     *
+     * See OP_MUL_LONG for an explanation.
+     *
+     * We get a little tight on registers, so to avoid looking up &fp[A]
+     * again we stuff it into rINST.
+     */
+    /* mul-long/2addr vA, vB */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
+    add     rINST, rFP, r9, lsl #2      @ rINST<- &fp[A]
+    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
+    ldmia   rINST, {r0-r1}              @ r0/r1<- vAA/vAA+1
+    mul     ip, r2, r1                  @  ip<- ZxW
+    umull   r9, r10, r2, r0             @  r9/r10 <- ZxX
+    mla     r2, r0, r3, ip              @  r2<- YxX + (ZxW)
+    mov     r0, rINST                   @ r0<- &fp[A] (free up rINST)
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    add     r10, r2, r10                @  r10<- r10 + low(ZxW + (YxX))
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r0, {r9-r10}                @ vAA/vAA+1<- r9/r10
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_LONG_2ADDR: /* 0xbe */
+/* File: armv6t2/OP_DIV_LONG_2ADDR.S */
+/* File: armv6t2/binopWide2addr.S */
+    /*
+     * Generic 64-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+     *      and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+     *      sub-double/2addr, mul-double/2addr, div-double/2addr,
+     *      rem-double/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    .if 1
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_ldivmod                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_LONG_2ADDR: /* 0xbf */
+/* File: armv6t2/OP_REM_LONG_2ADDR.S */
+/* ldivmod returns quotient in r0/r1 and remainder in r2/r3 */
+/* File: armv6t2/binopWide2addr.S */
+    /*
+     * Generic 64-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+     *      and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+     *      sub-double/2addr, mul-double/2addr, div-double/2addr,
+     *      rem-double/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    .if 1
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_ldivmod                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r2,r3}     @ vAA/vAA+1<- r2/r3
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AND_LONG_2ADDR: /* 0xc0 */
+/* File: armv6t2/OP_AND_LONG_2ADDR.S */
+/* File: armv6t2/binopWide2addr.S */
+    /*
+     * Generic 64-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+     *      and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+     *      sub-double/2addr, mul-double/2addr, div-double/2addr,
+     *      rem-double/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    .if 0
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+    and     r0, r0, r2                           @ optional op; may set condition codes
+    and     r1, r1, r3                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_OR_LONG_2ADDR: /* 0xc1 */
+/* File: armv6t2/OP_OR_LONG_2ADDR.S */
+/* File: armv6t2/binopWide2addr.S */
+    /*
+     * Generic 64-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+     *      and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+     *      sub-double/2addr, mul-double/2addr, div-double/2addr,
+     *      rem-double/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    .if 0
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+    orr     r0, r0, r2                           @ optional op; may set condition codes
+    orr     r1, r1, r3                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_XOR_LONG_2ADDR: /* 0xc2 */
+/* File: armv6t2/OP_XOR_LONG_2ADDR.S */
+/* File: armv6t2/binopWide2addr.S */
+    /*
+     * Generic 64-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+     *      and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+     *      sub-double/2addr, mul-double/2addr, div-double/2addr,
+     *      rem-double/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    .if 0
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+    eor     r0, r0, r2                           @ optional op; may set condition codes
+    eor     r1, r1, r3                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHL_LONG_2ADDR: /* 0xc3 */
+/* File: armv6t2/OP_SHL_LONG_2ADDR.S */
+    /*
+     * Long integer shift, 2addr version.  vA is 64-bit value/result, vB is
+     * 32-bit shift distance.
+     */
+    /* shl-long/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r2, r3)                    @ r2<- vB
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    and     r2, r2, #63                 @ r2<- r2 & 0x3f
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+
+    mov     r1, r1, asl r2              @  r1<- r1 << r2
+    rsb     r3, r2, #32                 @  r3<- 32 - r2
+    orr     r1, r1, r0, lsr r3          @  r1<- r1 | (r0 << (32-r2))
+    subs    ip, r2, #32                 @  ip<- r2 - 32
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    movpl   r1, r0, asl ip              @  if r2 >= 32, r1<- r0 << (r2-32)
+    mov     r0, r0, asl r2              @  r0<- r0 << r2
+    b       .LOP_SHL_LONG_2ADDR_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHR_LONG_2ADDR: /* 0xc4 */
+/* File: armv6t2/OP_SHR_LONG_2ADDR.S */
+    /*
+     * Long integer shift, 2addr version.  vA is 64-bit value/result, vB is
+     * 32-bit shift distance.
+     */
+    /* shr-long/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r2, r3)                    @ r2<- vB
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    and     r2, r2, #63                 @ r2<- r2 & 0x3f
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+
+    mov     r0, r0, lsr r2              @  r0<- r2 >> r2
+    rsb     r3, r2, #32                 @  r3<- 32 - r2
+    orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
+    subs    ip, r2, #32                 @  ip<- r2 - 32
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    movpl   r0, r1, asr ip              @  if r2 >= 32, r0<-r1 >> (r2-32)
+    mov     r1, r1, asr r2              @  r1<- r1 >> r2
+    b       .LOP_SHR_LONG_2ADDR_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_USHR_LONG_2ADDR: /* 0xc5 */
+/* File: armv6t2/OP_USHR_LONG_2ADDR.S */
+    /*
+     * Long integer shift, 2addr version.  vA is 64-bit value/result, vB is
+     * 32-bit shift distance.
+     */
+    /* ushr-long/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r2, r3)                    @ r2<- vB
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    and     r2, r2, #63                 @ r2<- r2 & 0x3f
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+
+    mov     r0, r0, lsr r2              @  r0<- r2 >> r2
+    rsb     r3, r2, #32                 @  r3<- 32 - r2
+    orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
+    subs    ip, r2, #32                 @  ip<- r2 - 32
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    movpl   r0, r1, lsr ip              @  if r2 >= 32, r0<-r1 >>> (r2-32)
+    mov     r1, r1, lsr r2              @  r1<- r1 >>> r2
+    b       .LOP_USHR_LONG_2ADDR_finish
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
+/* File: arm-vfp/OP_ADD_FLOAT_2ADDR.S */
+/* File: arm-vfp/fbinop2addr.S */
+    /*
+     * Generic 32-bit floating point "/2addr" binary operation.  Provide
+     * an "instr" line that specifies an instruction that performs
+     * "s2 = s0 op s1".
+     *
+     * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    and     r9, r9, #15                 @ r9<- A
+    flds    s1, [r3]                    @ s1<- vB
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    flds    s0, [r9]                    @ s0<- vA
+
+    fadds   s2, s0, s1                              @ s2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    fsts    s2, [r9]                    @ vAA<- s2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
+/* File: arm-vfp/OP_SUB_FLOAT_2ADDR.S */
+/* File: arm-vfp/fbinop2addr.S */
+    /*
+     * Generic 32-bit floating point "/2addr" binary operation.  Provide
+     * an "instr" line that specifies an instruction that performs
+     * "s2 = s0 op s1".
+     *
+     * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    and     r9, r9, #15                 @ r9<- A
+    flds    s1, [r3]                    @ s1<- vB
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    flds    s0, [r9]                    @ s0<- vA
+
+    fsubs   s2, s0, s1                              @ s2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    fsts    s2, [r9]                    @ vAA<- s2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
+/* File: arm-vfp/OP_MUL_FLOAT_2ADDR.S */
+/* File: arm-vfp/fbinop2addr.S */
+    /*
+     * Generic 32-bit floating point "/2addr" binary operation.  Provide
+     * an "instr" line that specifies an instruction that performs
+     * "s2 = s0 op s1".
+     *
+     * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    and     r9, r9, #15                 @ r9<- A
+    flds    s1, [r3]                    @ s1<- vB
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    flds    s0, [r9]                    @ s0<- vA
+
+    fmuls   s2, s0, s1                              @ s2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    fsts    s2, [r9]                    @ vAA<- s2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
+/* File: arm-vfp/OP_DIV_FLOAT_2ADDR.S */
+/* File: arm-vfp/fbinop2addr.S */
+    /*
+     * Generic 32-bit floating point "/2addr" binary operation.  Provide
+     * an "instr" line that specifies an instruction that performs
+     * "s2 = s0 op s1".
+     *
+     * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    and     r9, r9, #15                 @ r9<- A
+    flds    s1, [r3]                    @ s1<- vB
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    flds    s0, [r9]                    @ s0<- vA
+
+    fdivs   s2, s0, s1                              @ s2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    fsts    s2, [r9]                    @ vAA<- s2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_FLOAT_2ADDR: /* 0xca */
+/* File: armv6t2/OP_REM_FLOAT_2ADDR.S */
+/* EABI doesn't define a float remainder function, but libm does */
+/* File: armv6t2/binop2addr.S */
+    /*
+     * Generic 32-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+     *      rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+     *      shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+     *      sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r1, r3)                    @ r1<- vB
+    GET_VREG(r0, r9)                    @ r0<- vA
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    bl      fmodf                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
+/* File: arm-vfp/OP_ADD_DOUBLE_2ADDR.S */
+/* File: arm-vfp/fbinopWide2addr.S */
+    /*
+     * Generic 64-bit floating point "/2addr" binary operation.  Provide
+     * an "instr" line that specifies an instruction that performs
+     * "d2 = d0 op d1".
+     *
+     * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+     *      div-double/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    and     r9, r9, #15                 @ r9<- A
+    fldd    d1, [r3]                    @ d1<- vB
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    fldd    d0, [r9]                    @ d0<- vA
+
+    faddd   d2, d0, d1                              @ d2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    fstd    d2, [r9]                    @ vAA<- d2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
+/* File: arm-vfp/OP_SUB_DOUBLE_2ADDR.S */
+/* File: arm-vfp/fbinopWide2addr.S */
+    /*
+     * Generic 64-bit floating point "/2addr" binary operation.  Provide
+     * an "instr" line that specifies an instruction that performs
+     * "d2 = d0 op d1".
+     *
+     * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+     *      div-double/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    and     r9, r9, #15                 @ r9<- A
+    fldd    d1, [r3]                    @ d1<- vB
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    fldd    d0, [r9]                    @ d0<- vA
+
+    fsubd   d2, d0, d1                              @ d2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    fstd    d2, [r9]                    @ vAA<- d2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
+/* File: arm-vfp/OP_MUL_DOUBLE_2ADDR.S */
+/* File: arm-vfp/fbinopWide2addr.S */
+    /*
+     * Generic 64-bit floating point "/2addr" binary operation.  Provide
+     * an "instr" line that specifies an instruction that performs
+     * "d2 = d0 op d1".
+     *
+     * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+     *      div-double/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    and     r9, r9, #15                 @ r9<- A
+    fldd    d1, [r3]                    @ d1<- vB
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    fldd    d0, [r9]                    @ d0<- vA
+
+    fmuld   d2, d0, d1                              @ d2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    fstd    d2, [r9]                    @ vAA<- d2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_DOUBLE_2ADDR: /* 0xce */
+/* File: arm-vfp/OP_DIV_DOUBLE_2ADDR.S */
+/* File: arm-vfp/fbinopWide2addr.S */
+    /*
+     * Generic 64-bit floating point "/2addr" binary operation.  Provide
+     * an "instr" line that specifies an instruction that performs
+     * "d2 = d0 op d1".
+     *
+     * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+     *      div-double/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r3, rINST, lsr #12          @ r3<- B
+    mov     r9, rINST, lsr #8           @ r9<- A+
+    VREG_INDEX_TO_ADDR(r3, r3)          @ r3<- &vB
+    and     r9, r9, #15                 @ r9<- A
+    fldd    d1, [r3]                    @ d1<- vB
+    VREG_INDEX_TO_ADDR(r9, r9)          @ r9<- &vA
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+    fldd    d0, [r9]                    @ d0<- vA
+
+    fdivd   d2, d0, d1                              @ d2<- op
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    fstd    d2, [r9]                    @ vAA<- d2
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_DOUBLE_2ADDR: /* 0xcf */
+/* File: armv6t2/OP_REM_DOUBLE_2ADDR.S */
+/* EABI doesn't define a double remainder function, but libm does */
+/* File: armv6t2/binopWide2addr.S */
+    /*
+     * Generic 64-bit "/2addr" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+     *      and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+     *      sub-double/2addr, mul-double/2addr, div-double/2addr,
+     *      rem-double/2addr
+     */
+    /* binop/2addr vA, vB */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
+    ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
+    .if 0
+    orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(1)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    bl      fmod                              @ result<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0,r1}     @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_INT_LIT16: /* 0xd0 */
+/* File: armv6t2/OP_ADD_INT_LIT16.S */
+/* File: armv6t2/binopLit16.S */
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+     *      rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    FETCH_S(r1, 1)                      @ r1<- ssssCCCC (sign-extended)
+    mov     r2, rINST, lsr #12          @ r2<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r2)                    @ r0<- vB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    add     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RSUB_INT: /* 0xd1 */
+/* File: armv6t2/OP_RSUB_INT.S */
+/* this op is "rsub-int", but can be thought of as "rsub-int/lit16" */
+/* File: armv6t2/binopLit16.S */
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+     *      rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    FETCH_S(r1, 1)                      @ r1<- ssssCCCC (sign-extended)
+    mov     r2, rINST, lsr #12          @ r2<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r2)                    @ r0<- vB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    rsb     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_INT_LIT16: /* 0xd2 */
+/* File: armv6t2/OP_MUL_INT_LIT16.S */
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+/* File: armv6t2/binopLit16.S */
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+     *      rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    FETCH_S(r1, 1)                      @ r1<- ssssCCCC (sign-extended)
+    mov     r2, rINST, lsr #12          @ r2<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r2)                    @ r0<- vB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    mul     r0, r1, r0                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_INT_LIT16: /* 0xd3 */
+/* File: armv6t2/OP_DIV_INT_LIT16.S */
+/* File: armv6t2/binopLit16.S */
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+     *      rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    FETCH_S(r1, 1)                      @ r1<- ssssCCCC (sign-extended)
+    mov     r2, rINST, lsr #12          @ r2<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r2)                    @ r0<- vB
+    .if 1
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    bl     __aeabi_idiv                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_INT_LIT16: /* 0xd4 */
+/* File: armv6t2/OP_REM_INT_LIT16.S */
+/* idivmod returns quotient in r0 and remainder in r1 */
+/* File: armv6t2/binopLit16.S */
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+     *      rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    FETCH_S(r1, 1)                      @ r1<- ssssCCCC (sign-extended)
+    mov     r2, rINST, lsr #12          @ r2<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r2)                    @ r0<- vB
+    .if 1
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    bl      __aeabi_idivmod                              @ r1<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r1, r9)               @ vAA<- r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AND_INT_LIT16: /* 0xd5 */
+/* File: armv6t2/OP_AND_INT_LIT16.S */
+/* File: armv6t2/binopLit16.S */
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+     *      rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    FETCH_S(r1, 1)                      @ r1<- ssssCCCC (sign-extended)
+    mov     r2, rINST, lsr #12          @ r2<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r2)                    @ r0<- vB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    and     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_OR_INT_LIT16: /* 0xd6 */
+/* File: armv6t2/OP_OR_INT_LIT16.S */
+/* File: armv6t2/binopLit16.S */
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+     *      rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    FETCH_S(r1, 1)                      @ r1<- ssssCCCC (sign-extended)
+    mov     r2, rINST, lsr #12          @ r2<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r2)                    @ r0<- vB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    orr     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_XOR_INT_LIT16: /* 0xd7 */
+/* File: armv6t2/OP_XOR_INT_LIT16.S */
+/* File: armv6t2/binopLit16.S */
+    /*
+     * Generic 32-bit "lit16" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+     *      rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+     */
+    /* binop/lit16 vA, vB, #+CCCC */
+    FETCH_S(r1, 1)                      @ r1<- ssssCCCC (sign-extended)
+    mov     r2, rINST, lsr #12          @ r2<- B
+    ubfx    r9, rINST, #8, #4           @ r9<- A
+    GET_VREG(r0, r2)                    @ r0<- vB
+    .if 0
+    cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    eor     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_ADD_INT_LIT8: /* 0xd8 */
+/* File: armv5te/OP_ADD_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+     *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+     *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
+     */
+    /* binop/lit8 vAA, vBB, #+CC */
+    FETCH_S(r3, 1)                      @ r3<- ssssCCBB (sign-extended for CC)
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r3, #255                @ r2<- BB
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    movs    r1, r3, asr #8              @ r1<- ssssssCC (sign extended)
+    .if 0
+    @cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    add     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_RSUB_INT_LIT8: /* 0xd9 */
+/* File: armv5te/OP_RSUB_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+     *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+     *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
+     */
+    /* binop/lit8 vAA, vBB, #+CC */
+    FETCH_S(r3, 1)                      @ r3<- ssssCCBB (sign-extended for CC)
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r3, #255                @ r2<- BB
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    movs    r1, r3, asr #8              @ r1<- ssssssCC (sign extended)
+    .if 0
+    @cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    rsb     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_MUL_INT_LIT8: /* 0xda */
+/* File: armv5te/OP_MUL_INT_LIT8.S */
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+/* File: armv5te/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+     *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+     *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
+     */
+    /* binop/lit8 vAA, vBB, #+CC */
+    FETCH_S(r3, 1)                      @ r3<- ssssCCBB (sign-extended for CC)
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r3, #255                @ r2<- BB
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    movs    r1, r3, asr #8              @ r1<- ssssssCC (sign extended)
+    .if 0
+    @cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    mul     r0, r1, r0                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_DIV_INT_LIT8: /* 0xdb */
+/* File: armv5te/OP_DIV_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+     *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+     *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
+     */
+    /* binop/lit8 vAA, vBB, #+CC */
+    FETCH_S(r3, 1)                      @ r3<- ssssCCBB (sign-extended for CC)
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r3, #255                @ r2<- BB
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    movs    r1, r3, asr #8              @ r1<- ssssssCC (sign extended)
+    .if 1
+    @cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    bl     __aeabi_idiv                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_REM_INT_LIT8: /* 0xdc */
+/* File: armv5te/OP_REM_INT_LIT8.S */
+/* idivmod returns quotient in r0 and remainder in r1 */
+/* File: armv5te/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+     *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+     *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
+     */
+    /* binop/lit8 vAA, vBB, #+CC */
+    FETCH_S(r3, 1)                      @ r3<- ssssCCBB (sign-extended for CC)
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r3, #255                @ r2<- BB
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    movs    r1, r3, asr #8              @ r1<- ssssssCC (sign extended)
+    .if 1
+    @cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    bl      __aeabi_idivmod                              @ r1<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r1, r9)               @ vAA<- r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_AND_INT_LIT8: /* 0xdd */
+/* File: armv5te/OP_AND_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+     *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+     *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
+     */
+    /* binop/lit8 vAA, vBB, #+CC */
+    FETCH_S(r3, 1)                      @ r3<- ssssCCBB (sign-extended for CC)
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r3, #255                @ r2<- BB
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    movs    r1, r3, asr #8              @ r1<- ssssssCC (sign extended)
+    .if 0
+    @cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    and     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_OR_INT_LIT8: /* 0xde */
+/* File: armv5te/OP_OR_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+     *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+     *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
+     */
+    /* binop/lit8 vAA, vBB, #+CC */
+    FETCH_S(r3, 1)                      @ r3<- ssssCCBB (sign-extended for CC)
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r3, #255                @ r2<- BB
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    movs    r1, r3, asr #8              @ r1<- ssssssCC (sign extended)
+    .if 0
+    @cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    orr     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_XOR_INT_LIT8: /* 0xdf */
+/* File: armv5te/OP_XOR_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+     *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+     *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
+     */
+    /* binop/lit8 vAA, vBB, #+CC */
+    FETCH_S(r3, 1)                      @ r3<- ssssCCBB (sign-extended for CC)
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r3, #255                @ r2<- BB
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    movs    r1, r3, asr #8              @ r1<- ssssssCC (sign extended)
+    .if 0
+    @cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+                               @ optional op; may set condition codes
+    eor     r0, r0, r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHL_INT_LIT8: /* 0xe0 */
+/* File: armv5te/OP_SHL_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+     *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+     *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
+     */
+    /* binop/lit8 vAA, vBB, #+CC */
+    FETCH_S(r3, 1)                      @ r3<- ssssCCBB (sign-extended for CC)
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r3, #255                @ r2<- BB
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    movs    r1, r3, asr #8              @ r1<- ssssssCC (sign extended)
+    .if 0
+    @cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    and     r1, r1, #31                           @ optional op; may set condition codes
+    mov     r0, r0, asl r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_SHR_INT_LIT8: /* 0xe1 */
+/* File: armv5te/OP_SHR_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+     *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+     *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
+     */
+    /* binop/lit8 vAA, vBB, #+CC */
+    FETCH_S(r3, 1)                      @ r3<- ssssCCBB (sign-extended for CC)
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r3, #255                @ r2<- BB
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    movs    r1, r3, asr #8              @ r1<- ssssssCC (sign extended)
+    .if 0
+    @cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    and     r1, r1, #31                           @ optional op; may set condition codes
+    mov     r0, r0, asr r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_USHR_INT_LIT8: /* 0xe2 */
+/* File: armv5te/OP_USHR_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+    /*
+     * Generic 32-bit "lit8" binary operation.  Provide an "instr" line
+     * that specifies an instruction that performs "result = r0 op r1".
+     * This could be an ARM instruction or a function call.  (If the result
+     * comes back in a register other than r0, you can override "result".)
+     *
+     * If "chkzero" is set to 1, we perform a divide-by-zero check on
+     * vCC (r1).  Useful for integer division and modulus.
+     *
+     * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+     *      rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+     *      shl-int/lit8, shr-int/lit8, ushr-int/lit8
+     */
+    /* binop/lit8 vAA, vBB, #+CC */
+    FETCH_S(r3, 1)                      @ r3<- ssssCCBB (sign-extended for CC)
+    mov     r9, rINST, lsr #8           @ r9<- AA
+    and     r2, r3, #255                @ r2<- BB
+    GET_VREG(r0, r2)                    @ r0<- vBB
+    movs    r1, r3, asr #8              @ r1<- ssssssCC (sign extended)
+    .if 0
+    @cmp     r1, #0                      @ is second operand zero?
+    beq     common_errDivideByZero
+    .endif
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+
+    and     r1, r1, #31                           @ optional op; may set condition codes
+    mov     r0, r0, lsr r1                              @ r0<- op, r0-r3 changed
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)               @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+    /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E3: /* 0xe3 */
+/* File: armv5te/OP_UNUSED_E3.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E4: /* 0xe4 */
+/* File: armv5te/OP_UNUSED_E4.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E5: /* 0xe5 */
+/* File: armv5te/OP_UNUSED_E5.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E6: /* 0xe6 */
+/* File: armv5te/OP_UNUSED_E6.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E7: /* 0xe7 */
+/* File: armv5te/OP_UNUSED_E7.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E8: /* 0xe8 */
+/* File: armv5te/OP_UNUSED_E8.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_E9: /* 0xe9 */
+/* File: armv5te/OP_UNUSED_E9.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EA: /* 0xea */
+/* File: armv5te/OP_UNUSED_EA.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_EB: /* 0xeb */
+/* File: armv5te/OP_UNUSED_EB.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_BREAKPOINT: /* 0xec */
+/* File: armv5te/OP_BREAKPOINT.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: armv5te/OP_THROW_VERIFICATION_ERROR.S */
+    /*
+     * Handle a throw-verification-error instruction.  This throws an
+     * exception for an error discovered during verification.  The
+     * exception is indicated by AA, with some detail provided by BBBB.
+     */
+    /* op AA, ref@BBBB */
+    ldr     r0, [rGLUE, #offGlue_method]    @ r0<- glue->method
+    FETCH(r2, 1)                        @ r2<- BBBB
+    EXPORT_PC()                         @ export the PC
+    mov     r1, rINST, lsr #8           @ r1<- AA
+    bl      dvmThrowVerificationError   @ always throws
+    b       common_exceptionThrown      @ handle exception
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_EXECUTE_INLINE: /* 0xee */
+/* File: armv5te/OP_EXECUTE_INLINE.S */
+    /*
+     * Execute a "native inline" instruction.
+     *
+     * We need to call 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 vAA, {vC, vD, vE, vF}, inline@BBBB */
+    FETCH(r10, 1)                       @ r10<- BBBB
+    add     r1, rGLUE, #offGlue_retval  @ r1<- &glue->retval
+    EXPORT_PC()                         @ can throw
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #12          @ r0<- B
+    str     r1, [sp]                    @ push &glue->retval
+    bl      .LOP_EXECUTE_INLINE_continue        @ make call; will return after
+    add     sp, sp, #8                  @ pop stack
+    cmp     r0, #0                      @ test boolean result of inline
+    beq     common_exceptionThrown      @ returned false, handle exception
+    FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_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 */
+    FETCH(r10, 1)                       @ r10<- BBBB
+    add     r1, rGLUE, #offGlue_retval  @ r1<- &glue->retval
+    EXPORT_PC()                         @ can throw
+    sub     sp, sp, #8                  @ make room for arg, +64 bit align
+    mov     r0, rINST, lsr #8           @ r0<- AA
+    str     r1, [sp]                    @ push &glue->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_DIRECT_EMPTY: /* 0xf0 */
+/* File: armv5te/OP_INVOKE_DIRECT_EMPTY.S */
+    /*
+     * invoke-direct-empty is a no-op in a "standard" interpreter.
+     */
+    FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    GOTO_OPCODE(ip)                     @ execute it
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_F1: /* 0xf1 */
+/* File: armv5te/OP_UNUSED_F1.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_QUICK: /* 0xf2 */
+/* File: armv6t2/OP_IGET_QUICK.S */
+    /* For: iget-quick, iget-object-quick */
+    /* op vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    FETCH(r1, 1)                        @ r1<- field byte offset
+    GET_VREG(r3, r2)                    @ r3<- object we're operating on
+    ubfx    r2, rINST, #8, #4           @ r2<- A
+    cmp     r3, #0                      @ check object for null
+    beq     common_errNullObject        @ object was null
+    ldr     r0, [r3, r1]                @ r0<- obj.field (always 32 bits)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_WIDE_QUICK: /* 0xf3 */
+/* File: armv6t2/OP_IGET_WIDE_QUICK.S */
+    /* iget-wide-quick vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    FETCH(r1, 1)                        @ r1<- field byte offset
+    GET_VREG(r3, r2)                    @ r3<- object we're operating on
+    ubfx    r2, rINST, #8, #4           @ r2<- A
+    cmp     r3, #0                      @ check object for null
+    beq     common_errNullObject        @ object was null
+    ldrd    r0, [r3, r1]                @ r0<- obj.field (64 bits, aligned)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IGET_OBJECT_QUICK: /* 0xf4 */
+/* File: armv5te/OP_IGET_OBJECT_QUICK.S */
+/* File: armv5te/OP_IGET_QUICK.S */
+    /* For: iget-quick, iget-object-quick */
+    /* op vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    GET_VREG(r3, r2)                    @ r3<- object we're operating on
+    FETCH(r1, 1)                        @ r1<- field byte offset
+    cmp     r3, #0                      @ check object for null
+    mov     r2, rINST, lsr #8           @ r2<- A(+)
+    beq     common_errNullObject        @ object was null
+    ldr     r0, [r3, r1]                @ r0<- obj.field (always 32 bits)
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_QUICK: /* 0xf5 */
+/* File: armv6t2/OP_IPUT_QUICK.S */
+    /* For: iput-quick, iput-object-quick */
+    /* op vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    FETCH(r1, 1)                        @ r1<- field byte offset
+    GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
+    ubfx    r2, rINST, #8, #4           @ r2<- A
+    cmp     r3, #0                      @ check object for null
+    beq     common_errNullObject        @ object was null
+    GET_VREG(r0, r2)                    @ r0<- fp[A]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    str     r0, [r3, r1]                @ obj.field (always 32 bits)<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
+/* File: armv6t2/OP_IPUT_WIDE_QUICK.S */
+    /* iput-wide-quick vA, vB, offset@CCCC */
+    mov     r1, rINST, lsr #12          @ r1<- B
+    ubfx    r0, rINST, #8, #4           @ r0<- A
+    GET_VREG(r2, r1)                    @ r2<- fp[B], the object pointer
+    add     r3, rFP, r0, lsl #2         @ r3<- &fp[A]
+    cmp     r2, #0                      @ check object for null
+    ldmia   r3, {r0-r1}                 @ r0/r1<- fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH(r3, 1)                        @ r3<- field byte offset
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    strd    r0, [r2, r3]                @ obj.field (64 bits, aligned)<- r0/r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_IPUT_OBJECT_QUICK: /* 0xf7 */
+/* File: armv5te/OP_IPUT_OBJECT_QUICK.S */
+/* File: armv5te/OP_IPUT_QUICK.S */
+    /* For: iput-quick, iput-object-quick */
+    /* op vA, vB, offset@CCCC */
+    mov     r2, rINST, lsr #12          @ r2<- B
+    GET_VREG(r3, r2)                    @ r3<- fp[B], the object pointer
+    FETCH(r1, 1)                        @ r1<- field byte offset
+    cmp     r3, #0                      @ check object for null
+    mov     r2, rINST, lsr #8           @ r2<- A(+)
+    beq     common_errNullObject        @ object was null
+    and     r2, r2, #15
+    GET_VREG(r0, r2)                    @ r0<- fp[A]
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    str     r0, [r3, r1]                @ obj.field (always 32 bits)<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
+/* File: armv5te/OP_INVOKE_VIRTUAL_QUICK.S */
+    /*
+     * Handle an optimized virtual method call.
+     *
+     * for: [opt] invoke-virtual-quick, invoke-virtual-quick/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    FETCH(r3, 2)                        @ r3<- FEDC or CCCC
+    FETCH(r1, 1)                        @ r1<- BBBB
+    .if     (!0)
+    and     r3, r3, #15                 @ r3<- C (or stays CCCC)
+    .endif
+    GET_VREG(r2, r3)                    @ r2<- vC ("this" ptr)
+    cmp     r2, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r2, [r2, #offObject_clazz]  @ r2<- thisPtr->clazz
+    ldr     r2, [r2, #offClassObject_vtable]    @ r2<- thisPtr->clazz->vtable
+    EXPORT_PC()                         @ invoke must export
+    ldr     r0, [r2, r1, lsl #2]        @ r3<- vtable[BBBB]
+    bl      common_invokeMethodNoRange @ continue on
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
+/* File: armv5te/OP_INVOKE_VIRTUAL_QUICK_RANGE.S */
+/* File: armv5te/OP_INVOKE_VIRTUAL_QUICK.S */
+    /*
+     * Handle an optimized virtual method call.
+     *
+     * for: [opt] invoke-virtual-quick, invoke-virtual-quick/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    FETCH(r3, 2)                        @ r3<- FEDC or CCCC
+    FETCH(r1, 1)                        @ r1<- BBBB
+    .if     (!1)
+    and     r3, r3, #15                 @ r3<- C (or stays CCCC)
+    .endif
+    GET_VREG(r2, r3)                    @ r2<- vC ("this" ptr)
+    cmp     r2, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r2, [r2, #offObject_clazz]  @ r2<- thisPtr->clazz
+    ldr     r2, [r2, #offClassObject_vtable]    @ r2<- thisPtr->clazz->vtable
+    EXPORT_PC()                         @ invoke must export
+    ldr     r0, [r2, r1, lsl #2]        @ r3<- vtable[BBBB]
+    bl      common_invokeMethodRange @ continue on
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_SUPER_QUICK: /* 0xfa */
+/* File: armv5te/OP_INVOKE_SUPER_QUICK.S */
+    /*
+     * Handle an optimized "super" method call.
+     *
+     * for: [opt] invoke-super-quick, invoke-super-quick/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    FETCH(r10, 2)                       @ r10<- GFED or CCCC
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    .if     (!0)
+    and     r10, r10, #15               @ r10<- D (or stays CCCC)
+    .endif
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r2, [r2, #offMethod_clazz]  @ r2<- method->clazz
+    EXPORT_PC()                         @ must export for invoke
+    ldr     r2, [r2, #offClassObject_super]     @ r2<- method->clazz->super
+    GET_VREG(r3, r10)                   @ r3<- "this"
+    ldr     r2, [r2, #offClassObject_vtable]    @ r2<- ...clazz->super->vtable
+    cmp     r3, #0                      @ null "this" ref?
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- super->vtable[BBBB]
+    beq     common_errNullObject        @ "this" is null, throw exception
+    bl      common_invokeMethodNoRange @ continue on
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
+/* File: armv5te/OP_INVOKE_SUPER_QUICK_RANGE.S */
+/* File: armv5te/OP_INVOKE_SUPER_QUICK.S */
+    /*
+     * Handle an optimized "super" method call.
+     *
+     * for: [opt] invoke-super-quick, invoke-super-quick/range
+     */
+    /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+    /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+    FETCH(r10, 2)                       @ r10<- GFED or CCCC
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    .if     (!1)
+    and     r10, r10, #15               @ r10<- D (or stays CCCC)
+    .endif
+    FETCH(r1, 1)                        @ r1<- BBBB
+    ldr     r2, [r2, #offMethod_clazz]  @ r2<- method->clazz
+    EXPORT_PC()                         @ must export for invoke
+    ldr     r2, [r2, #offClassObject_super]     @ r2<- method->clazz->super
+    GET_VREG(r3, r10)                   @ r3<- "this"
+    ldr     r2, [r2, #offClassObject_vtable]    @ r2<- ...clazz->super->vtable
+    cmp     r3, #0                      @ null "this" ref?
+    ldr     r0, [r2, r1, lsl #2]        @ r0<- super->vtable[BBBB]
+    beq     common_errNullObject        @ "this" is null, throw exception
+    bl      common_invokeMethodRange @ continue on
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_FC: /* 0xfc */
+/* File: armv5te/OP_UNUSED_FC.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_FD: /* 0xfd */
+/* File: armv5te/OP_UNUSED_FD.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_FE: /* 0xfe */
+/* File: armv5te/OP_UNUSED_FE.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+/* ------------------------------ */
+    .balign 64
+.L_OP_UNUSED_FF: /* 0xff */
+/* File: armv5te/OP_UNUSED_FF.S */
+/* File: armv5te/unused.S */
+    bl      common_abort
+
+
+
+
+    .balign 64
+    .size   dvmAsmInstructionStart, .-dvmAsmInstructionStart
+    .global dvmAsmInstructionEnd
+dvmAsmInstructionEnd:
+
+/*
+ * ===========================================================================
+ *  Sister implementations
+ * ===========================================================================
+ */
+    .global dvmAsmSisterStart
+    .type   dvmAsmSisterStart, %function
+    .text
+    .balign 4
+dvmAsmSisterStart:
+
+/* continuation for OP_CONST_STRING */
+
+    /*
+     * Continuation if the String has not yet been resolved.
+     *  r1: BBBB (String ref)
+     *  r9: target register
+     */
+.LOP_CONST_STRING_resolve:
+    EXPORT_PC()
+    ldr     r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+    ldr     r0, [r0, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveString            @ r0<- String reference
+    cmp     r0, #0                      @ failed?
+    beq     common_exceptionThrown      @ yup, handle the exception
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_CONST_STRING_JUMBO */
+
+    /*
+     * Continuation if the String has not yet been resolved.
+     *  r1: BBBBBBBB (String ref)
+     *  r9: target register
+     */
+.LOP_CONST_STRING_JUMBO_resolve:
+    EXPORT_PC()
+    ldr     r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+    ldr     r0, [r0, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveString            @ r0<- String reference
+    cmp     r0, #0                      @ failed?
+    beq     common_exceptionThrown      @ yup, handle the exception
+    FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_CONST_CLASS */
+
+    /*
+     * Continuation if the Class has not yet been resolved.
+     *  r1: BBBB (Class ref)
+     *  r9: target register
+     */
+.LOP_CONST_CLASS_resolve:
+    EXPORT_PC()
+    ldr     r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+    mov     r2, #1                      @ r2<- true
+    ldr     r0, [r0, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveClass             @ r0<- Class reference
+    cmp     r0, #0                      @ failed?
+    beq     common_exceptionThrown      @ yup, handle the exception
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_CHECK_CAST */
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds class resolved from BBBB
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_fullcheck:
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    cmp     r0, #0                      @ failed?
+    bne     .LOP_CHECK_CAST_okay            @ no, success
+
+    @ A cast has failed.  We need to throw a ClassCastException with the
+    @ class of the object that failed to be cast.
+    EXPORT_PC()                         @ about to throw
+    ldr     r3, [r9, #offObject_clazz]  @ r3<- obj->clazz
+    ldr     r0, .LstrClassCastExceptionPtr
+    ldr     r1, [r3, #offClassObject_descriptor] @ r1<- obj->clazz->descriptor
+    bl      dvmThrowExceptionWithClassMessage
+    b       common_exceptionThrown
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r2 holds BBBB
+     *  r9 holds object
+     */
+.LOP_CHECK_CAST_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+    mov     r1, r2                      @ r1<- BBBB
+    mov     r2, #0                      @ r2<- false
+    ldr     r0, [r3, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveClass             @ r0<- resolved ClassObject ptr
+    cmp     r0, #0                      @ got null?
+    beq     common_exceptionThrown      @ yes, handle exception
+    mov     r1, r0                      @ r1<- class resolved from BBB
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
+    b       .LOP_CHECK_CAST_resolved        @ pick up where we left off
+
+.LstrClassCastExceptionPtr:
+    .word   .LstrClassCastException
+
+
+/* continuation for OP_INSTANCE_OF */
+
+    /*
+     * Trivial test failed, need to perform full check.  This is common.
+     *  r0 holds obj->clazz
+     *  r1 holds class resolved from BBBB
+     *  r9 holds A
+     */
+.LOP_INSTANCE_OF_fullcheck:
+    bl      dvmInstanceofNonTrivial     @ r0<- boolean result
+    @ fall through to OP_INSTANCE_OF_store
+
+    /*
+     * r0 holds boolean result
+     * r9 holds A
+     */
+.LOP_INSTANCE_OF_store:
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r0, r9)                    @ vA<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * Trivial test succeeded, save and bail.
+     *  r9 holds A
+     */
+.LOP_INSTANCE_OF_trivial:
+    mov     r0, #1                      @ indicate success
+    @ could b OP_INSTANCE_OF_store, but copying is faster and cheaper
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r0, r9)                    @ vA<- r0
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r3 holds BBBB
+     *  r9 holds A
+     */
+.LOP_INSTANCE_OF_resolve:
+    EXPORT_PC()                         @ resolve() could throw
+    ldr     r0, [rGLUE, #offGlue_method]    @ r0<- glue->method
+    mov     r1, r3                      @ r1<- BBBB
+    mov     r2, #1                      @ r2<- true
+    ldr     r0, [r0, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveClass             @ r0<- resolved ClassObject ptr
+    cmp     r0, #0                      @ got null?
+    beq     common_exceptionThrown      @ yes, handle exception
+    mov     r1, r0                      @ r1<- class resolved from BBB
+    mov     r3, rINST, lsr #12          @ r3<- B
+    GET_VREG(r0, r3)                    @ r0<- vB (object)
+    ldr     r0, [r0, #offObject_clazz]  @ r0<- obj->clazz
+    b       .LOP_INSTANCE_OF_resolved        @ pick up where we left off
+
+
+/* continuation for OP_NEW_INSTANCE */
+
+    .balign 32                          @ minimize cache lines
+.LOP_NEW_INSTANCE_finish: @ r0=new object
+    mov     r3, rINST, lsr #8           @ r3<- AA
+    cmp     r0, #0                      @ failed?
+    beq     common_exceptionThrown      @ yes, handle the exception
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r3)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+    /*
+     * Class initialization required.
+     *
+     *  r0 holds class object
+     */
+.LOP_NEW_INSTANCE_needinit:
+    mov     r9, r0                      @ save r0
+    bl      dvmInitClass                @ initialize class
+    cmp     r0, #0                      @ check boolean result
+    mov     r0, r9                      @ restore r0
+    bne     .LOP_NEW_INSTANCE_initialized     @ success, continue
+    b       common_exceptionThrown      @ failed, deal with init exception
+
+    /*
+     * Resolution required.  This is the least-likely path.
+     *
+     *  r1 holds BBBB
+     */
+.LOP_NEW_INSTANCE_resolve:
+    ldr     r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+    mov     r2, #0                      @ r2<- false
+    ldr     r0, [r3, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveClass             @ r0<- resolved ClassObject ptr
+    cmp     r0, #0                      @ got null?
+    bne     .LOP_NEW_INSTANCE_resolved        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+.LstrInstantiationErrorPtr:
+    .word   .LstrInstantiationError
+
+
+/* continuation for OP_NEW_ARRAY */
+
+
+    /*
+     * Resolve class.  (This is an uncommon case.)
+     *
+     *  r1 holds array length
+     *  r2 holds class ref CCCC
+     */
+.LOP_NEW_ARRAY_resolve:
+    ldr     r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+    mov     r9, r1                      @ r9<- length (save)
+    mov     r1, r2                      @ r1<- CCCC
+    mov     r2, #0                      @ r2<- false
+    ldr     r0, [r3, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveClass             @ r0<- call(clazz, ref)
+    cmp     r0, #0                      @ got null?
+    mov     r1, r9                      @ r1<- length (restore)
+    beq     common_exceptionThrown      @ yes, handle exception
+    @ fall through to OP_NEW_ARRAY_finish
+
+    /*
+     * Finish allocation.
+     *
+     *  r0 holds class
+     *  r1 holds array length
+     */
+.LOP_NEW_ARRAY_finish:
+    mov     r2, #ALLOC_DONT_TRACK       @ don't track in local refs table
+    bl      dvmAllocArrayByClass        @ r0<- call(clazz, length, flags)
+    cmp     r0, #0                      @ failed?
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    beq     common_exceptionThrown      @ yes, handle the exception
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ vA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_FILLED_NEW_ARRAY */
+
+    /*
+     * On entry:
+     *  r0 holds array class
+     *  r10 holds AA or BA
+     */
+.LOP_FILLED_NEW_ARRAY_continue:
+    ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
+    mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
+    ldrb    r3, [r3, #1]                @ r3<- descriptor[1]
+    .if     0
+    mov     r1, r10                     @ r1<- AA (length)
+    .else
+    mov     r1, r10, lsr #4             @ r1<- B (length)
+    .endif
+    cmp     r3, #'I'                    @ array of ints?
+    cmpne   r3, #'L'                    @ array of objects?
+    cmpne   r3, #'['                    @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_notimpl         @ no, not handled yet
+    bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
+    cmp     r0, #0                      @ null return?
+    beq     common_exceptionThrown      @ alloc failed, handle exception
+
+    FETCH(r1, 2)                        @ r1<- FEDC or CCCC
+    str     r0, [rGLUE, #offGlue_retval]    @ retval.l <- new array
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
+    bmi     2f                          @ was zero, bail
+
+    @ copy values from registers into the array
+    @ r0=array, r1=CCCC/FEDC, r9=length (from AA or B), r10=AA/BA
+    .if     0
+    add     r2, rFP, r1, lsl #2         @ r2<- &fp[CCCC]
+1:  ldr     r3, [r2], #4                @ r3<- *r2++
+    subs    r9, r9, #1                  @ count--
+    str     r3, [r0], #4                @ *contents++ = vX
+    bpl     1b
+    @ continue at 2
+    .else
+    cmp     r9, #4                      @ length was initially 5?
+    and     r2, r10, #15                @ r2<- A
+    bne     1f                          @ <= 4 args, branch
+    GET_VREG(r3, r2)                    @ r3<- vA
+    sub     r9, r9, #1                  @ count--
+    str     r3, [r0, #16]               @ contents[4] = vA
+1:  and     r2, r1, #15                 @ r2<- F/E/D/C
+    GET_VREG(r3, r2)                    @ r3<- vF/vE/vD/vC
+    mov     r1, r1, lsr #4              @ r1<- next reg in low 4
+    subs    r9, r9, #1                  @ count--
+    str     r3, [r0], #4                @ *contents++ = vX
+    bpl     1b
+    @ continue at 2
+    .endif
+
+2:
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    GOTO_OPCODE(ip)                     @ execute it
+
+    /*
+     * Throw an exception indicating that we have not implemented this
+     * mode of filled-new-array.
+     */
+.LOP_FILLED_NEW_ARRAY_notimpl:
+    ldr     r0, .L_strInternalError
+    ldr     r1, .L_strFilledNewArrayNotImpl
+    bl      dvmThrowException
+    b       common_exceptionThrown
+
+    .if     (!0)                 @ define in one or the other, not both
+.L_strFilledNewArrayNotImpl:
+    .word   .LstrFilledNewArrayNotImpl
+.L_strInternalError:
+    .word   .LstrInternalError
+    .endif
+
+
+/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
+
+    /*
+     * On entry:
+     *  r0 holds array class
+     *  r10 holds AA or BA
+     */
+.LOP_FILLED_NEW_ARRAY_RANGE_continue:
+    ldr     r3, [r0, #offClassObject_descriptor] @ r3<- arrayClass->descriptor
+    mov     r2, #ALLOC_DONT_TRACK       @ r2<- alloc flags
+    ldrb    r3, [r3, #1]                @ r3<- descriptor[1]
+    .if     1
+    mov     r1, r10                     @ r1<- AA (length)
+    .else
+    mov     r1, r10, lsr #4             @ r1<- B (length)
+    .endif
+    cmp     r3, #'I'                    @ array of ints?
+    cmpne   r3, #'L'                    @ array of objects?
+    cmpne   r3, #'['                    @ array of arrays?
+    mov     r9, r1                      @ save length in r9
+    bne     .LOP_FILLED_NEW_ARRAY_RANGE_notimpl         @ no, not handled yet
+    bl      dvmAllocArrayByClass        @ r0<- call(arClass, length, flags)
+    cmp     r0, #0                      @ null return?
+    beq     common_exceptionThrown      @ alloc failed, handle exception
+
+    FETCH(r1, 2)                        @ r1<- FEDC or CCCC
+    str     r0, [rGLUE, #offGlue_retval]    @ retval.l <- new array
+    add     r0, r0, #offArrayObject_contents @ r0<- newArray->contents
+    subs    r9, r9, #1                  @ length--, check for neg
+    FETCH_ADVANCE_INST(3)               @ advance to next instr, load rINST
+    bmi     2f                          @ was zero, bail
+
+    @ copy values from registers into the array
+    @ r0=array, r1=CCCC/FEDC, r9=length (from AA or B), r10=AA/BA
+    .if     1
+    add     r2, rFP, r1, lsl #2         @ r2<- &fp[CCCC]
+1:  ldr     r3, [r2], #4                @ r3<- *r2++
+    subs    r9, r9, #1                  @ count--
+    str     r3, [r0], #4                @ *contents++ = vX
+    bpl     1b
+    @ continue at 2
+    .else
+    cmp     r9, #4                      @ length was initially 5?
+    and     r2, r10, #15                @ r2<- A
+    bne     1f                          @ <= 4 args, branch
+    GET_VREG(r3, r2)                    @ r3<- vA
+    sub     r9, r9, #1                  @ count--
+    str     r3, [r0, #16]               @ contents[4] = vA
+1:  and     r2, r1, #15                 @ r2<- F/E/D/C
+    GET_VREG(r3, r2)                    @ r3<- vF/vE/vD/vC
+    mov     r1, r1, lsr #4              @ r1<- next reg in low 4
+    subs    r9, r9, #1                  @ count--
+    str     r3, [r0], #4                @ *contents++ = vX
+    bpl     1b
+    @ continue at 2
+    .endif
+
+2:
+    GET_INST_OPCODE(ip)                 @ ip<- opcode from rINST
+    GOTO_OPCODE(ip)                     @ execute it
+
+    /*
+     * Throw an exception indicating that we have not implemented this
+     * mode of filled-new-array.
+     */
+.LOP_FILLED_NEW_ARRAY_RANGE_notimpl:
+    ldr     r0, .L_strInternalError
+    ldr     r1, .L_strFilledNewArrayNotImpl
+    bl      dvmThrowException
+    b       common_exceptionThrown
+
+    .if     (!1)                 @ define in one or the other, not both
+.L_strFilledNewArrayNotImpl:
+    .word   .LstrFilledNewArrayNotImpl
+.L_strInternalError:
+    .word   .LstrInternalError
+    .endif
+
+
+/* continuation for OP_CMPL_FLOAT */
+.LOP_CMPL_FLOAT_finish:
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_CMPG_FLOAT */
+.LOP_CMPG_FLOAT_finish:
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_CMPL_DOUBLE */
+.LOP_CMPL_DOUBLE_finish:
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_CMPG_DOUBLE */
+.LOP_CMPG_DOUBLE_finish:
+    SET_VREG(r0, r9)                    @ vAA<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_CMP_LONG */
+
+.LOP_CMP_LONG_less:
+    mvn     r1, #0                      @ r1<- -1
+    @ Want to cond code the next mov so we can avoid branch, but don't see it;
+    @ instead, we just replicate the tail end.
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r9)                    @ vAA<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+.LOP_CMP_LONG_greater:
+    mov     r1, #1                      @ r1<- 1
+    @ fall through to _finish
+
+.LOP_CMP_LONG_finish:
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    SET_VREG(r1, r9)                    @ vAA<- r1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_AGET_WIDE */
+
+.LOP_AGET_WIDE_finish:
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldrd    r2, [r0, #offArrayObject_contents]  @ r2/r3<- vBB[vCC]
+    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r2-r3}                 @ vAA/vAA+1<- r2/r3
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_APUT_WIDE */
+
+.LOP_APUT_WIDE_finish:
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r9, {r2-r3}                 @ r2/r3<- vAA/vAA+1
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    strd    r2, [r0, #offArrayObject_contents]  @ r2/r3<- vBB[vCC]
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_APUT_OBJECT */
+    /*
+     * On entry:
+     *  r1 = vBB (arrayObj)
+     *  r9 = vAA (obj)
+     *  r10 = offset into array (vBB + vCC * width)
+     */
+.LOP_APUT_OBJECT_finish:
+    cmp     r9, #0                      @ storing null reference?
+    beq     .LOP_APUT_OBJECT_skip_check      @ yes, skip type checks
+    ldr     r0, [r9, #offObject_clazz]  @ r0<- obj->clazz
+    ldr     r1, [r1, #offObject_clazz]  @ r1<- arrayObj->clazz
+    bl      dvmCanPutArrayElement       @ test object type vs. array type
+    cmp     r0, #0                      @ okay?
+    beq     common_errArrayStore        @ no
+.LOP_APUT_OBJECT_skip_check:
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str     r9, [r10, #offArrayObject_contents] @ vBB[vCC]<- vAA
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IGET */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    ubfx    r2, rINST, #8, #4           @ r2<- A
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IGET_WIDE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_WIDE_finish:
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldrd    r0, [r9, r3]                @ r0/r1<- obj.field (64-bit align ok)
+    ubfx    r2, rINST, #8, #4           @ r2<- A
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IGET_OBJECT */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_OBJECT_finish:
+    @bl      common_squeak0
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IGET_BOOLEAN */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BOOLEAN_finish:
+    @bl      common_squeak1
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IGET_BYTE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_BYTE_finish:
+    @bl      common_squeak2
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IGET_CHAR */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_CHAR_finish:
+    @bl      common_squeak3
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IGET_SHORT */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IGET_SHORT_finish:
+    @bl      common_squeak4
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    beq     common_errNullObject        @ object was null
+    ldr   r0, [r9, r3]                @ r0<- obj.field (8/16/32 bits)
+    mov     r2, rINST, lsr #8           @ r2<- A+
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    and     r2, r2, #15                 @ r2<- A
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    SET_VREG(r0, r2)                    @ fp[A]<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IPUT */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_finish:
+    @bl      common_squeak0
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    ubfx    r1, rINST, #8, #4           @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IPUT_WIDE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_WIDE_finish:
+    ubfx    r2, rINST, #8, #4           @ r2<- A
+    cmp     r9, #0                      @ check object for null
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    add     r2, rFP, r2, lsl #2         @ r3<- &fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    ldmia   r2, {r0-r1}                 @ r0/r1<- fp[A]
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    strd    r0, [r9, r3]                @ obj.field (64 bits, aligned)<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IPUT_OBJECT */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_OBJECT_finish:
+    @bl      common_squeak0
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IPUT_BOOLEAN */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BOOLEAN_finish:
+    @bl      common_squeak1
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IPUT_BYTE */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_BYTE_finish:
+    @bl      common_squeak2
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IPUT_CHAR */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_CHAR_finish:
+    @bl      common_squeak3
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_IPUT_SHORT */
+
+    /*
+     * Currently:
+     *  r0 holds resolved field
+     *  r9 holds object
+     */
+.LOP_IPUT_SHORT_finish:
+    @bl      common_squeak4
+    mov     r1, rINST, lsr #8           @ r1<- A+
+    ldr     r3, [r0, #offInstField_byteOffset]  @ r3<- byte offset of field
+    and     r1, r1, #15                 @ r1<- A
+    cmp     r9, #0                      @ check object for null
+    GET_VREG(r0, r1)                    @ r0<- fp[A]
+    beq     common_errNullObject        @ object was null
+    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    str  r0, [r9, r3]                @ obj.field (8/16/32 bits)<- r0
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_SGET */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     */
+.LOP_SGET_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SGET_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_SGET_WIDE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     */
+.LOP_SGET_WIDE_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SGET_WIDE_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_SGET_OBJECT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     */
+.LOP_SGET_OBJECT_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SGET_OBJECT_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_SGET_BOOLEAN */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     */
+.LOP_SGET_BOOLEAN_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SGET_BOOLEAN_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_SGET_BYTE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     */
+.LOP_SGET_BYTE_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SGET_BYTE_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_SGET_CHAR */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     */
+.LOP_SGET_CHAR_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SGET_CHAR_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_SGET_SHORT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     */
+.LOP_SGET_SHORT_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SGET_SHORT_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_SPUT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     */
+.LOP_SPUT_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_SPUT_WIDE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     *  r9: &fp[AA]
+     */
+.LOP_SPUT_WIDE_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_WIDE_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_SPUT_OBJECT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     */
+.LOP_SPUT_OBJECT_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_OBJECT_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_SPUT_BOOLEAN */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     */
+.LOP_SPUT_BOOLEAN_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_BOOLEAN_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_SPUT_BYTE */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     */
+.LOP_SPUT_BYTE_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_BYTE_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_SPUT_CHAR */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     */
+.LOP_SPUT_CHAR_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_CHAR_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_SPUT_SHORT */
+
+    /*
+     * Continuation if the field has not yet been resolved.
+     *  r1: BBBB field ref
+     */
+.LOP_SPUT_SHORT_resolve:
+    ldr     r2, [rGLUE, #offGlue_method]    @ r2<- current method
+    EXPORT_PC()                         @ resolve() could throw, so export now
+    ldr     r0, [r2, #offMethod_clazz]  @ r0<- method->clazz
+    bl      dvmResolveStaticField       @ r0<- resolved StaticField ptr
+    cmp     r0, #0                      @ success?
+    bne     .LOP_SPUT_SHORT_finish          @ yes, finish
+    b       common_exceptionThrown      @ no, handle exception
+
+
+/* continuation for OP_INVOKE_VIRTUAL */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = C or CCCC (index of first arg, which is the "this" ptr)
+     */
+.LOP_INVOKE_VIRTUAL_continue:
+    GET_VREG(r1, r10)                   @ r1<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r1, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r1, #offObject_clazz]  @ r1<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodNoRange @ continue on
+
+
+/* continuation for OP_INVOKE_SUPER */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r9 = method->clazz
+     */
+.LOP_INVOKE_SUPER_continue:
+    ldr     r1, [r9, #offClassObject_super]     @ r1<- method->clazz->super
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    ldr     r3, [r1, #offClassObject_vtableCount]   @ r3<- super->vtableCount
+    EXPORT_PC()                         @ must export for invoke
+    cmp     r2, r3                      @ compare (methodIndex, vtableCount)
+    bcs     .LOP_INVOKE_SUPER_nsm             @ method not present in superclass
+    ldr     r1, [r1, #offClassObject_vtable]    @ r1<- ...clazz->super->vtable
+    ldr     r0, [r1, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodNoRange @ continue on
+
+.LOP_INVOKE_SUPER_resolve:
+    mov     r0, r9                      @ r0<- method->clazz
+    mov     r2, #METHOD_VIRTUAL         @ resolver method type
+    bl      dvmResolveMethod            @ r0<- call(clazz, ref, flags)
+    cmp     r0, #0                      @ got null?
+    bne     .LOP_INVOKE_SUPER_continue        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+    /*
+     * Throw a NoSuchMethodError with the method name as the message.
+     *  r0 = resolved base method
+     */
+.LOP_INVOKE_SUPER_nsm:
+    ldr     r1, [r0, #offMethod_name]   @ r1<- method name
+    b       common_errNoSuchMethod
+
+
+/* continuation for OP_INVOKE_DIRECT */
+
+    /*
+     * On entry:
+     *  r1 = reference (BBBB or CCCC)
+     *  r10 = "this" register
+     */
+.LOP_INVOKE_DIRECT_resolve:
+    ldr     r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+    ldr     r0, [r3, #offMethod_clazz]  @ r0<- method->clazz
+    mov     r2, #METHOD_DIRECT          @ resolver method type
+    bl      dvmResolveMethod            @ r0<- call(clazz, ref, flags)
+    cmp     r0, #0                      @ got null?
+    GET_VREG(r2, r10)                   @ r2<- "this" ptr (reload)
+    bne     .LOP_INVOKE_DIRECT_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+
+/* continuation for OP_INVOKE_VIRTUAL_RANGE */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r10 = C or CCCC (index of first arg, which is the "this" ptr)
+     */
+.LOP_INVOKE_VIRTUAL_RANGE_continue:
+    GET_VREG(r1, r10)                   @ r1<- "this" ptr
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    cmp     r1, #0                      @ is "this" null?
+    beq     common_errNullObject        @ null "this", throw exception
+    ldr     r3, [r1, #offObject_clazz]  @ r1<- thisPtr->clazz
+    ldr     r3, [r3, #offClassObject_vtable]    @ r3<- thisPtr->clazz->vtable
+    ldr     r0, [r3, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodRange @ continue on
+
+
+/* continuation for OP_INVOKE_SUPER_RANGE */
+
+    /*
+     * At this point:
+     *  r0 = resolved base method
+     *  r9 = method->clazz
+     */
+.LOP_INVOKE_SUPER_RANGE_continue:
+    ldr     r1, [r9, #offClassObject_super]     @ r1<- method->clazz->super
+    ldrh    r2, [r0, #offMethod_methodIndex]    @ r2<- baseMethod->methodIndex
+    ldr     r3, [r1, #offClassObject_vtableCount]   @ r3<- super->vtableCount
+    EXPORT_PC()                         @ must export for invoke
+    cmp     r2, r3                      @ compare (methodIndex, vtableCount)
+    bcs     .LOP_INVOKE_SUPER_RANGE_nsm             @ method not present in superclass
+    ldr     r1, [r1, #offClassObject_vtable]    @ r1<- ...clazz->super->vtable
+    ldr     r0, [r1, r2, lsl #2]        @ r3<- vtable[methodIndex]
+    bl      common_invokeMethodRange @ continue on
+
+.LOP_INVOKE_SUPER_RANGE_resolve:
+    mov     r0, r9                      @ r0<- method->clazz
+    mov     r2, #METHOD_VIRTUAL         @ resolver method type
+    bl      dvmResolveMethod            @ r0<- call(clazz, ref, flags)
+    cmp     r0, #0                      @ got null?
+    bne     .LOP_INVOKE_SUPER_RANGE_continue        @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+    /*
+     * Throw a NoSuchMethodError with the method name as the message.
+     *  r0 = resolved base method
+     */
+.LOP_INVOKE_SUPER_RANGE_nsm:
+    ldr     r1, [r0, #offMethod_name]   @ r1<- method name
+    b       common_errNoSuchMethod
+
+
+/* continuation for OP_INVOKE_DIRECT_RANGE */
+
+    /*
+     * On entry:
+     *  r1 = reference (BBBB or CCCC)
+     *  r10 = "this" register
+     */
+.LOP_INVOKE_DIRECT_RANGE_resolve:
+    ldr     r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+    ldr     r0, [r3, #offMethod_clazz]  @ r0<- method->clazz
+    mov     r2, #METHOD_DIRECT          @ resolver method type
+    bl      dvmResolveMethod            @ r0<- call(clazz, ref, flags)
+    cmp     r0, #0                      @ got null?
+    GET_VREG(r2, r10)                   @ r2<- "this" ptr (reload)
+    bne     .LOP_INVOKE_DIRECT_RANGE_finish          @ no, continue
+    b       common_exceptionThrown      @ yes, handle exception
+
+
+/* continuation for OP_FLOAT_TO_LONG */
+/*
+ * Convert the float in r0 to a long in r0/r1.
+ *
+ * We have to clip values to long min/max per the specification.  The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer.  The EABI convert function isn't doing this for us.
+ */
+f2l_doconv:
+    stmfd   sp!, {r4, lr}
+    mov     r1, #0x5f000000             @ (float)maxlong
+    mov     r4, r0
+    bl      __aeabi_fcmpge              @ is arg >= maxlong?
+    cmp     r0, #0                      @ nonzero == yes
+    mvnne   r0, #0                      @ return maxlong (7fffffff)
+    mvnne   r1, #0x80000000
+    ldmnefd sp!, {r4, pc}
+
+    mov     r0, r4                      @ recover arg
+    mov     r1, #0xdf000000             @ (float)minlong
+    bl      __aeabi_fcmple              @ is arg <= minlong?
+    cmp     r0, #0                      @ nonzero == yes
+    movne   r0, #0                      @ return minlong (80000000)
+    movne   r1, #0x80000000
+    ldmnefd sp!, {r4, pc}
+
+    mov     r0, r4                      @ recover arg
+    mov     r1, r4
+    bl      __aeabi_fcmpeq              @ is arg == self?
+    cmp     r0, #0                      @ zero == no
+    moveq   r1, #0                      @ return zero for NaN
+    ldmeqfd sp!, {r4, pc}
+
+    mov     r0, r4                      @ recover arg
+    bl      __aeabi_f2lz                @ convert float to long
+    ldmfd   sp!, {r4, pc}
+
+
+/* continuation for OP_DOUBLE_TO_LONG */
+/*
+ * Convert the double in r0/r1 to a long in r0/r1.
+ *
+ * We have to clip values to long min/max per the specification.  The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer.  The EABI convert function isn't doing this for us.
+ */
+d2l_doconv:
+    stmfd   sp!, {r4, r5, lr}           @ save regs
+    mov     r3, #0x43000000             @ maxlong, as a double (high word)
+    add     r3, #0x00e00000             @  0x43e00000
+    mov     r2, #0                      @ maxlong, as a double (low word)
+    sub     sp, sp, #4                  @ align for EABI
+    mov     r4, r0                      @ save a copy of r0
+    mov     r5, r1                      @  and r1
+    bl      __aeabi_dcmpge              @ is arg >= maxlong?
+    cmp     r0, #0                      @ nonzero == yes
+    mvnne   r0, #0                      @ return maxlong (7fffffffffffffff)
+    mvnne   r1, #0x80000000
+    bne     1f
+
+    mov     r0, r4                      @ recover arg
+    mov     r1, r5
+    mov     r3, #0xc3000000             @ minlong, as a double (high word)
+    add     r3, #0x00e00000             @  0xc3e00000
+    mov     r2, #0                      @ minlong, as a double (low word)
+    bl      __aeabi_dcmple              @ is arg <= minlong?
+    cmp     r0, #0                      @ nonzero == yes
+    movne   r0, #0                      @ return minlong (8000000000000000)
+    movne   r1, #0x80000000
+    bne     1f
+
+    mov     r0, r4                      @ recover arg
+    mov     r1, r5
+    mov     r2, r4                      @ compare against self
+    mov     r3, r5
+    bl      __aeabi_dcmpeq              @ is arg == self?
+    cmp     r0, #0                      @ zero == no
+    moveq   r1, #0                      @ return zero for NaN
+    beq     1f
+
+    mov     r0, r4                      @ recover arg
+    mov     r1, r5
+    bl      __aeabi_d2lz                @ convert double to long
+
+1:
+    add     sp, sp, #4
+    ldmfd   sp!, {r4, r5, pc}
+
+
+/* continuation for OP_MUL_LONG */
+
+.LOP_MUL_LONG_finish:
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r0, {r9-r10}                @ vAA/vAA+1<- r9/r10
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_SHL_LONG */
+
+.LOP_SHL_LONG_finish:
+    mov     r0, r0, asl r2              @  r0<- r0 << r2
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_SHR_LONG */
+
+.LOP_SHR_LONG_finish:
+    mov     r1, r1, asr r2              @  r1<- r1 >> r2
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_USHR_LONG */
+
+.LOP_USHR_LONG_finish:
+    mov     r1, r1, lsr r2              @  r1<- r1 >>> r2
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_SHL_LONG_2ADDR */
+
+.LOP_SHL_LONG_2ADDR_finish:
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_SHR_LONG_2ADDR */
+
+.LOP_SHR_LONG_2ADDR_finish:
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_USHR_LONG_2ADDR */
+
+.LOP_USHR_LONG_2ADDR_finish:
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+
+/* continuation for OP_EXECUTE_INLINE */
+
+    /*
+     * Extract args, call function.
+     *  r0 = #of args (0-4)
+     *  r10 = call index
+     *  lr = return addr, above  [DO NOT bl out of here w/o preserving LR]
+     *
+     * Other ideas:
+     * - Use a jump table from the main piece to jump directly into the
+     *   AND/LDR pairs.  Costs a data load, saves a branch.
+     * - Have five separate pieces that do the loading, so we can work the
+     *   interleave a little better.  Increases code size.
+     */
+.LOP_EXECUTE_INLINE_continue:
+    rsb     r0, r0, #4                  @ r0<- 4-r0
+    FETCH(r9, 2)                        @ r9<- FEDC
+    add     pc, pc, r0, lsl #3          @ computed goto, 2 instrs each
+    bl      common_abort                @ (skipped due to ARM prefetch)
+4:  and     ip, r9, #0xf000             @ isolate F
+    ldr     r3, [rFP, ip, lsr #10]      @ r3<- vF (shift right 12, left 2)
+3:  and     ip, r9, #0x0f00             @ isolate E
+    ldr     r2, [rFP, ip, lsr #6]       @ r2<- vE
+2:  and     ip, r9, #0x00f0             @ isolate D
+    ldr     r1, [rFP, ip, lsr #2]       @ r1<- vD
+1:  and     ip, r9, #0x000f             @ isolate C
+    ldr     r0, [rFP, ip, lsl #2]       @ r0<- vC
+0:
+    ldr     r9, .LOP_EXECUTE_INLINE_table       @ table of InlineOperation
+    LDR_PC  "[r9, r10, lsl #4]"         @ sizeof=16, "func" is first entry
+    @ (not reached)
+
+.LOP_EXECUTE_INLINE_table:
+    .word   gDvmInlineOpsTable
+
+
+/* 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)
+
+.LOP_EXECUTE_INLINE_RANGE_table:
+    .word   gDvmInlineOpsTable
+
+
+    .size   dvmAsmSisterStart, .-dvmAsmSisterStart
+    .global dvmAsmSisterEnd
+dvmAsmSisterEnd:
+
+/* File: armv5te/footer.S */
+
+/*
+ * ===========================================================================
+ *  Common subroutines and data
+ * ===========================================================================
+ */
+
+
+
+    .text
+    .align  2
+
+#if defined(WITH_JIT)
+#if defined(WITH_SELF_VERIFICATION)
+    .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+    mov    r2,#kSVSPunt                 @ r2<- interpreter entry point
+    b      dvmJitSelfVerificationEnd    @ doesn't return
+
+    .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+    mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
+    b      dvmJitSelfVerificationEnd    @ doesn't return
+
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSTraceSelectNoChain   @ r2<- interpreter entry point
+    b      dvmJitSelfVerificationEnd    @ doesn't return
+
+    .global dvmJitToInterpTraceSelect
+dvmJitToInterpTraceSelect:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
+    b      dvmJitSelfVerificationEnd    @ doesn't return
+
+    .global dvmJitToInterpBackwardBranch
+dvmJitToInterpBackwardBranch:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
+    b      dvmJitSelfVerificationEnd    @ doesn't return
+
+    .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+    ldr    r0,[lr, #-1]                 @ pass our target PC
+    mov    r2,#kSVSNormal               @ r2<- interpreter entry point
+    b      dvmJitSelfVerificationEnd    @ doesn't return
+
+    .global dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+    mov    r0,rPC                       @ pass our target PC
+    mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
+    b      dvmJitSelfVerificationEnd    @ doesn't return
+#else
+/*
+ * 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:
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    rPC, r0
+#ifdef JIT_STATS
+    mov    r0,lr
+    bl     dvmBumpPunt;
+#endif
+    EXPORT_PC()
+    mov    r0, #0
+    str    r0, [r10, #offThread_inJitCodeCache] @ Back to the interp land
+    adrl   rIBASE, dvmAsmInstructionStart
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+
+/*
+ * Return to the interpreter to handle a single instruction.
+ * On entry:
+ *    r0 <= PC
+ *    r1 <= PC of resume instruction
+ *    lr <= resume point in translation
+ */
+    .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+    str    lr,[rGLUE,#offGlue_jitResume]
+    str    r1,[rGLUE,#offGlue_jitResumePC]
+    mov    r1,#kInterpEntryInstr
+    @ enum is 4 byte in aapcs-EABI
+    str    r1, [rGLUE, #offGlue_entryPoint]
+    mov    rPC,r0
+    EXPORT_PC()
+
+    adrl   rIBASE, dvmAsmInstructionStart
+    mov    r2,#kJitSingleStep     @ Ask for single step and then revert
+    str    r2,[rGLUE,#offGlue_jitState]
+    mov    r1,#1                  @ set changeInterp to bail to debug interp
+    b      common_gotoBail
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target.  Commonly used for callees.
+ */
+    .global dvmJitToInterpTraceSelectNoChain
+dvmJitToInterpTraceSelectNoChain:
+#ifdef JIT_STATS
+    bl     dvmBumpNoChain
+#endif
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC
+    bl     dvmJitGetCodeAddr        @ Is there a translation?
+    str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+    b      2f
+
+/*
+ * 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
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    add    rINST,lr,#-5            @ save start of chain branch
+    mov    r0,rPC
+    bl     dvmJitGetCodeAddr       @ Is there a translation?
+    str    r0, [r10, #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:
+    adrl   rIBASE, dvmAsmInstructionStart
+    GET_JIT_PROF_TABLE(r0)
+    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
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    add    rINST,lr,#-5            @ save start of chain branch
+#ifdef JIT_STATS
+    bl     dvmBumpNormal
+#endif
+    mov    r0,rPC
+    bl     dvmJitGetCodeAddr        @ Is there a translation?
+    str    r0, [r10, #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 dvmJitToInterpNoChain
+dvmJitToInterpNoChain:
+#ifdef JIT_STATS
+    bl     dvmBumpNoChain
+#endif
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r0,rPC
+    bl     dvmJitGetCodeAddr        @ Is there a translation?
+    str    r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov    r1, rPC                  @ arg1 of translation may need this
+    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
+    cmp    r0,#0
+    bxne   r0                       @ continue native execution if so
+#endif
+
+/*
+ * No translation, restore interpreter regs and start interpreting.
+ * rGLUE & rFP were preserved in the translated code, and rPC has
+ * already been restored by the time we get here.  We'll need to set
+ * up rIBASE & rINST, and load the address of the JitTable into r0.
+ */
+toInterpreter:
+    EXPORT_PC()
+    adrl   rIBASE, dvmAsmInstructionStart
+    FETCH_INST()
+    GET_JIT_PROF_TABLE(r0)
+    @ NOTE: intended fallthrough
+/*
+ * Common code to update potential trace start counter, and initiate
+ * a trace-build if appropriate.  On entry, rPC should point to the
+ * next instruction to execute, and rINST should be already loaded with
+ * the next opcode word, and r0 holds a pointer to the jit profile
+ * table (pJitProfTable).
+ */
+common_testUpdateProfile:
+    cmp     r0,#0
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE_IFEQ(ip)       @ if not profiling, fallthrough otherwise */
+
+common_updateProfile:
+    eor     r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
+    lsl     r3,r3,#(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 */
+
+/*
+ * 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(r1)
+    ldr     r10, [rGLUE, #offGlue_self] @ callee saved r10 <- glue->self
+    strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ reset counter
+    EXPORT_PC()
+    mov     r0,rPC
+    bl      dvmJitGetCodeAddr           @ r0<- dvmJitGetCodeAddr(rPC)
+    str     r0, [r10, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
+    mov     r1, rPC                     @ arg1 of translation may need this
+    mov     lr, #0                      @  in case target is HANDLER_INTERPRET
+    cmp     r0,#0
+#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     dvmJitSelfVerificationStart  @ set up self verification
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+    /* no return */
+#endif
+
+/*
+ * On entry:
+ *  r2 is jit state, e.g. kJitTSelectRequest or kJitTSelectRequestHot
+ */
+common_selectTrace:
+    str     r2,[rGLUE,#offGlue_jitState]
+    mov     r2,#kInterpEntryInstr       @ normal entry reason
+    str     r2,[rGLUE,#offGlue_entryPoint]
+    mov     r1,#1                       @ set changeInterp
+    b       common_gotoBail
+
+#if defined(WITH_SELF_VERIFICATION)
+/*
+ * Save PC and registers to shadow memory for self verification mode
+ * before jumping to native translation.
+ * On entry, r10 contains the address of the target translation.
+ */
+dvmJitSelfVerificationStart:
+    mov     r0,rPC                      @ r0<- program counter
+    mov     r1,rFP                      @ r1<- frame pointer
+    mov     r2,rGLUE                    @ r2<- InterpState pointer
+    mov     r3,r10                      @ r3<- target translation
+    bl      dvmSelfVerificationSaveState @ save registers to shadow space
+    ldr     rFP,[r0,#offShadowSpace_shadowFP] @ rFP<- fp in shadow space
+    add     rGLUE,r0,#offShadowSpace_interpState @ rGLUE<- rGLUE in shadow space
+    bx      r10                         @ jump to the translation
+
+/*
+ * Restore PC, registers, and interpState to original values
+ * before jumping back to the interpreter.
+ */
+dvmJitSelfVerificationEnd:
+    ldr    r10, [rGLUE, #offGlue_self]  @ callee saved r10 <- glue->self
+    mov    r1, #0
+    str    r1, [r10, #offThread_inJitCodeCache] @ Back to the interp land
+    mov    r1,rFP                        @ pass ending fp
+    bl     dvmSelfVerificationRestoreState @ restore pc and fp values
+    ldr    rPC,[r0,#offShadowSpace_startPC] @ restore PC
+    ldr    rFP,[r0,#offShadowSpace_fp]   @ restore FP
+    ldr    rGLUE,[r0,#offShadowSpace_glue] @ restore InterpState
+    ldr    r1,[r0,#offShadowSpace_svState] @ get self verification state
+    cmp    r1,#0                         @ check for punt condition
+    beq    1f
+    mov    r2,#kJitSelfVerification      @ ask for self verification
+    str    r2,[rGLUE,#offGlue_jitState]
+    mov    r2,#kInterpEntryInstr         @ normal entry reason
+    str    r2,[rGLUE,#offGlue_entryPoint]
+    mov    r1,#1                         @ set changeInterp
+    b      common_gotoBail
+
+1:                                       @ exit to interpreter without check
+    EXPORT_PC()
+    adrl   rIBASE, dvmAsmInstructionStart
+    FETCH_INST()
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+#endif
+
+#endif
+
+/*
+ * Common code when a backward branch is taken.
+ *
+ * On entry:
+ *  r9 is PC adjustment *in bytes*
+ */
+common_backwardBranch:
+    mov     r0, #kInterpEntryInstr
+    bl      common_periodicChecks
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    cmp     r0,#0
+    bne     common_updateProfile
+    GET_INST_OPCODE(ip)
+    GOTO_OPCODE(ip)
+#else
+    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+
+/*
+ * Need to see if the thread needs to be suspended or debugger/profiler
+ * activity has begun.
+ *
+ * TODO: if JDWP isn't running, zero out pDebuggerActive pointer so we don't
+ * have to do the second ldr.
+ *
+ * TODO: reduce this so we're just checking a single location.
+ *
+ * On entry:
+ *  r0 is reentry type, e.g. kInterpEntryInstr
+ *  r9 is trampoline PC adjustment *in bytes*
+ */
+common_periodicChecks:
+    ldr     r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
+
+    @ speculatively store r0 before it is clobbered by dvmCheckSuspendPending
+    str     r0, [rGLUE, #offGlue_entryPoint]
+
+#if defined(WITH_DEBUGGER)
+    ldr     r1, [rGLUE, #offGlue_pDebuggerActive]   @ r1<- &debuggerActive
+#endif
+#if defined(WITH_PROFILER)
+    ldr     r2, [rGLUE, #offGlue_pActiveProfilers]  @ r2<- &activeProfilers
+#endif
+
+    ldr     r3, [r3]                    @ r3<- suspendCount (int)
+
+#if defined(WITH_DEBUGGER)
+    ldrb    r1, [r1]                    @ r1<- debuggerActive (boolean)
+#endif
+#if defined (WITH_PROFILER)
+    ldr     r2, [r2]                    @ r2<- activeProfilers (int)
+#endif
+
+    cmp     r3, #0                      @ suspend pending?
+    bne     2f                          @ yes, do full suspension check
+
+#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
+# if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
+    orrs    r1, r1, r2                  @ r1<- r1 | r2
+    cmp     r1, #0                      @ debugger attached or profiler started?
+# elif defined(WITH_DEBUGGER)
+    cmp     r1, #0                      @ debugger attached?
+# elif defined(WITH_PROFILER)
+    cmp     r2, #0                      @ profiler started?
+# endif
+    bne     3f                          @ debugger/profiler, switch interp
+#endif
+
+    bx      lr                          @ nothing to do, return
+
+2:  @ check suspend
+#if defined(WITH_JIT)
+    /*
+     * Refresh the Jit's cached copy of profile table pointer.  This pointer
+     * doubles as the Jit's on/off switch.
+     */
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable] @ r10<-&gDvmJit.pJitProfTable
+    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    ldr     r3, [r3] @ r10 <- pJitProfTable
+    EXPORT_PC()                         @ need for precise GC
+    str     r3, [rGLUE, #offGlue_pJitProfTable] @ refresh Jit's on/off switch
+#else
+    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
+    EXPORT_PC()                         @ need for precise GC
+#endif
+    b       dvmCheckSuspendPending      @ suspend if necessary, then return
+
+3:  @ debugger/profiler enabled, bail out
+    add     rPC, rPC, r9                @ update rPC
+    mov     r1, #1                      @ "want switch" = true
+    b       common_gotoBail
+
+
+/*
+ * The equivalent of "goto bail", this calls through the "bail handler".
+ *
+ * State registers will be saved to the "glue" area before bailing.
+ *
+ * On entry:
+ *  r1 is "bool changeInterp", indicating if we want to switch to the
+ *     other interpreter or just bail all the way out
+ */
+common_gotoBail:
+    SAVE_PC_FP_TO_GLUE()                @ export state to "glue"
+    mov     r0, rGLUE                   @ r0<- glue ptr
+    b       dvmMterpStdBail             @ call(glue, changeInterp)
+
+    @add     r1, r1, #1                  @ using (boolean+1)
+    @add     r0, rGLUE, #offGlue_jmpBuf  @ r0<- &glue->jmpBuf
+    @bl      _longjmp                    @ does not return
+    @bl      common_abort
+
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ *  r0 is "Method* methodToCall", the method we're trying to call
+ */
+common_invokeMethodRange:
+.LinvokeNewRange:
+    @ prepare to copy args to "outs" area of current frame
+    movs    r2, rINST, lsr #8           @ r2<- AA (arg count) -- test for zero
+    SAVEAREA_FROM_FP(r10, rFP)          @ r10<- stack save area
+    beq     .LinvokeArgsDone            @ if no args, skip the rest
+    FETCH(r1, 2)                        @ r1<- CCCC
+
+    @ r0=methodToCall, r1=CCCC, r2=count, r10=outs
+    @ (very few methods have > 10 args; could unroll for common cases)
+    add     r3, rFP, r1, lsl #2         @ r3<- &fp[CCCC]
+    sub     r10, r10, r2, lsl #2        @ r10<- "outs" area, for call args
+    ldrh    r9, [r0, #offMethod_registersSize]  @ r9<- methodToCall->regsSize
+1:  ldr     r1, [r3], #4                @ val = *fp++
+    subs    r2, r2, #1                  @ count--
+    str     r1, [r10], #4               @ *outs++ = val
+    bne     1b                          @ ...while count != 0
+    ldrh    r3, [r0, #offMethod_outsSize]   @ r3<- methodToCall->outsSize
+    b       .LinvokeArgsDone
+
+/*
+ * Common code for method invocation without range.
+ *
+ * On entry:
+ *  r0 is "Method* methodToCall", the method we're trying to call
+ */
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+    @ prepare to copy args to "outs" area of current frame
+    movs    r2, rINST, lsr #12          @ r2<- B (arg count) -- test for zero
+    SAVEAREA_FROM_FP(r10, rFP)          @ r10<- stack save area
+    FETCH(r1, 2)                        @ r1<- GFED (load here to hide latency)
+    ldrh    r9, [r0, #offMethod_registersSize]  @ r9<- methodToCall->regsSize
+    ldrh    r3, [r0, #offMethod_outsSize]  @ r3<- methodToCall->outsSize
+    beq     .LinvokeArgsDone
+
+    @ r0=methodToCall, r1=GFED, r3=outSize, r2=count, r9=regSize, r10=outs
+.LinvokeNonRange:
+    rsb     r2, r2, #5                  @ r2<- 5-r2
+    add     pc, pc, r2, lsl #4          @ computed goto, 4 instrs each
+    bl      common_abort                @ (skipped due to ARM prefetch)
+5:  and     ip, rINST, #0x0f00          @ isolate A
+    ldr     r2, [rFP, ip, lsr #6]       @ r2<- vA (shift right 8, left 2)
+    mov     r0, r0                      @ nop
+    str     r2, [r10, #-4]!             @ *--outs = vA
+4:  and     ip, r1, #0xf000             @ isolate G
+    ldr     r2, [rFP, ip, lsr #10]      @ r2<- vG (shift right 12, left 2)
+    mov     r0, r0                      @ nop
+    str     r2, [r10, #-4]!             @ *--outs = vG
+3:  and     ip, r1, #0x0f00             @ isolate F
+    ldr     r2, [rFP, ip, lsr #6]       @ r2<- vF
+    mov     r0, r0                      @ nop
+    str     r2, [r10, #-4]!             @ *--outs = vF
+2:  and     ip, r1, #0x00f0             @ isolate E
+    ldr     r2, [rFP, ip, lsr #2]       @ r2<- vE
+    mov     r0, r0                      @ nop
+    str     r2, [r10, #-4]!             @ *--outs = vE
+1:  and     ip, r1, #0x000f             @ isolate D
+    ldr     r2, [rFP, ip, lsl #2]       @ r2<- vD
+    mov     r0, r0                      @ nop
+    str     r2, [r10, #-4]!             @ *--outs = vD
+0:  @ fall through to .LinvokeArgsDone
+
+.LinvokeArgsDone: @ r0=methodToCall, r3=outSize, r9=regSize
+    ldr     r2, [r0, #offMethod_insns]  @ r2<- method->insns
+    ldr     rINST, [r0, #offMethod_clazz]  @ rINST<- method->clazz
+    @ find space for the new stack frame, check for overflow
+    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
+    sub     r1, r1, r9, lsl #2          @ r1<- newFp (old savearea - regsSize)
+    SAVEAREA_FROM_FP(r10, r1)           @ r10<- newSaveArea
+@    bl      common_dumpRegs
+    ldr     r9, [rGLUE, #offGlue_interpStackEnd]    @ r9<- interpStackEnd
+    sub     r3, r10, r3, lsl #2         @ r3<- bottom (newsave - outsSize)
+    cmp     r3, r9                      @ bottom < interpStackEnd?
+    ldr     r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
+    blt     .LstackOverflow             @ yes, this frame will overflow stack
+
+    @ set up newSaveArea
+#ifdef EASY_GDB
+    SAVEAREA_FROM_FP(ip, rFP)           @ ip<- stack save area
+    str     ip, [r10, #offStackSaveArea_prevSave]
+#endif
+    str     rFP, [r10, #offStackSaveArea_prevFrame]
+    str     rPC, [r10, #offStackSaveArea_savedPc]
+#if defined(WITH_JIT)
+    mov     r9, #0
+    str     r9, [r10, #offStackSaveArea_returnAddr]
+#endif
+    str     r0, [r10, #offStackSaveArea_method]
+    tst     r3, #ACC_NATIVE
+    bne     .LinvokeNative
+
+    /*
+    stmfd   sp!, {r0-r3}
+    bl      common_printNewline
+    mov     r0, rFP
+    mov     r1, #0
+    bl      dvmDumpFp
+    ldmfd   sp!, {r0-r3}
+    stmfd   sp!, {r0-r3}
+    mov     r0, r1
+    mov     r1, r10
+    bl      dvmDumpFp
+    bl      common_printNewline
+    ldmfd   sp!, {r0-r3}
+    */
+
+    ldrh    r9, [r2]                        @ r9 <- load INST from new PC
+    ldr     r3, [rINST, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+    mov     rPC, r2                         @ publish new rPC
+    ldr     r2, [rGLUE, #offGlue_self]      @ r2<- glue->self
+
+    @ Update "glue" values for the new method
+    @ r0=methodToCall, r1=newFp, r2=self, r3=newMethodClass, r9=newINST
+    str     r0, [rGLUE, #offGlue_method]    @ glue->method = methodToCall
+    str     r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+#if defined(WITH_JIT)
+    GET_JIT_PROF_TABLE(r0)
+    mov     rFP, r1                         @ fp = newFp
+    GET_PREFETCHED_OPCODE(ip, r9)           @ extract prefetched opcode from r9
+    mov     rINST, r9                       @ publish new rINST
+    str     r1, [r2, #offThread_curFrame]   @ self->curFrame = newFp
+    cmp     r0,#0
+    bne     common_updateProfile
+    GOTO_OPCODE(ip)                         @ jump to next instruction
+#else
+    mov     rFP, r1                         @ fp = newFp
+    GET_PREFETCHED_OPCODE(ip, r9)           @ extract prefetched opcode from r9
+    mov     rINST, r9                       @ publish new rINST
+    str     r1, [r2, #offThread_curFrame]   @ self->curFrame = newFp
+    GOTO_OPCODE(ip)                         @ jump to next instruction
+#endif
+
+.LinvokeNative:
+    @ Prep for the native call
+    @ r0=methodToCall, r1=newFp, r10=newSaveArea
+    ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
+    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
+    str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
+    str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
+    mov     r9, r3                      @ r9<- glue->self (preserve)
+
+    mov     r2, r0                      @ r2<- methodToCall
+    mov     r0, r1                      @ r0<- newFp (points to args)
+    add     r1, rGLUE, #offGlue_retval  @ r1<- &retval
+
+#ifdef ASSIST_DEBUGGER
+    /* insert fake function header to help gdb find the stack frame */
+    b       .Lskip
+    .type   dalvik_mterp, %function
+dalvik_mterp:
+    .fnstart
+    MTERP_ENTRY1
+    MTERP_ENTRY2
+.Lskip:
+#endif
+
+    @mov     lr, pc                      @ set return addr
+    @ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+    LDR_PC_LR "[r2, #offMethod_nativeFunc]"
+
+#if defined(WITH_JIT)
+    ldr     r3, [rGLUE, #offGlue_ppJitProfTable] @ Refresh Jit's on/off status
+#endif
+
+    @ native return; r9=self, r10=newSaveArea
+    @ equivalent to dvmPopJniLocals
+    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
+    ldr     r1, [r9, #offThread_exception] @ check for exception
+#if defined(WITH_JIT)
+    ldr     r3, [r3]                    @ r3 <- gDvmJit.pProfTable
+#endif
+    str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
+    cmp     r1, #0                      @ null?
+    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
+#if defined(WITH_JIT)
+    str     r3, [rGLUE, #offGlue_pJitProfTable] @ refresh cached on/off switch
+#endif
+    bne     common_exceptionThrown      @ no, handle exception
+
+    FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+.LstackOverflow:    @ r0=methodToCall
+    mov     r1, r0                      @ r1<- methodToCall
+    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- self
+    bl      dvmHandleStackOverflow
+    b       common_exceptionThrown
+#ifdef ASSIST_DEBUGGER
+    .fnend
+#endif
+
+
+    /*
+     * Common code for method invocation, calling through "glue code".
+     *
+     * TODO: now that we have range and non-range invoke handlers, this
+     *       needs to be split into two.  Maybe just create entry points
+     *       that set r9 and jump here?
+     *
+     * On entry:
+     *  r0 is "Method* methodToCall", the method we're trying to call
+     *  r9 is "bool methodCallRange", indicating if this is a /range variant
+     */
+     .if    0
+.LinvokeOld:
+    sub     sp, sp, #8                  @ space for args + pad
+    FETCH(ip, 2)                        @ ip<- FEDC or CCCC
+    mov     r2, r0                      @ A2<- methodToCall
+    mov     r0, rGLUE                   @ A0<- glue
+    SAVE_PC_FP_TO_GLUE()                @ export state to "glue"
+    mov     r1, r9                      @ A1<- methodCallRange
+    mov     r3, rINST, lsr #8           @ A3<- AA
+    str     ip, [sp, #0]                @ A4<- ip
+    bl      dvmMterp_invokeMethod       @ call the C invokeMethod
+    add     sp, sp, #8                  @ remove arg area
+    b       common_resumeAfterGlueCall  @ continue to next instruction
+    .endif
+
+
+
+/*
+ * Common code for handling a return instruction.
+ *
+ * This does not return.
+ */
+common_returnFromMethod:
+.LreturnNew:
+    mov     r0, #kInterpEntryReturn
+    mov     r9, #0
+    bl      common_periodicChecks
+
+    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
+    ldr     rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
+    ldr     r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
+    ldr     r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
+                                        @ r2<- method we're returning to
+    ldr     r3, [rGLUE, #offGlue_self]  @ r3<- glue->self
+    cmp     r2, #0                      @ is this a break frame?
+    ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+    mov     r1, #0                      @ "want switch" = false
+    beq     common_gotoBail             @ break frame, bail out completely
+
+    PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
+    str     r2, [rGLUE, #offGlue_method]@ glue->method = newSave->method
+    ldr     r1, [r10, #offClassObject_pDvmDex]   @ r1<- method->clazz->pDvmDex
+    str     rFP, [r3, #offThread_curFrame]  @ self->curFrame = fp
+#if defined(WITH_JIT)
+    ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
+    GET_JIT_PROF_TABLE(r0)
+    mov     rPC, r9                     @ publish new rPC
+    str     r1, [rGLUE, #offGlue_methodClassDex]
+    str     r10, [r3, #offThread_inJitCodeCache]  @ may return to JIT'ed land
+    cmp     r10, #0                      @ caller is compiled code
+    blxne   r10
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    cmp     r0,#0
+    bne     common_updateProfile
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#else
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    mov     rPC, r9                     @ publish new rPC
+    str     r1, [rGLUE, #offGlue_methodClassDex]
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+#endif
+
+    /*
+     * Return handling, calls through "glue code".
+     */
+     .if    0
+.LreturnOld:
+    SAVE_PC_FP_TO_GLUE()                @ export state
+    mov     r0, rGLUE                   @ arg to function
+    bl      dvmMterp_returnFromMethod
+    b       common_resumeAfterGlueCall
+    .endif
+
+
+/*
+ * Somebody has thrown an exception.  Handle it.
+ *
+ * If the exception processing code returns to us (instead of falling
+ * out of the interpreter), continue with whatever the next instruction
+ * now happens to be.
+ *
+ * This does not return.
+ */
+     .global dvmMterpCommonExceptionThrown
+dvmMterpCommonExceptionThrown:
+common_exceptionThrown:
+.LexceptionNew:
+    mov     r0, #kInterpEntryThrow
+    mov     r9, #0
+    bl      common_periodicChecks
+
+    ldr     r10, [rGLUE, #offGlue_self] @ r10<- glue->self
+    ldr     r9, [r10, #offThread_exception] @ r9<- self->exception
+    mov     r1, r10                     @ r1<- self
+    mov     r0, r9                      @ r0<- exception
+    bl      dvmAddTrackedAlloc          @ don't let the exception be GCed
+    mov     r3, #0                      @ r3<- NULL
+    str     r3, [r10, #offThread_exception] @ self->exception = NULL
+
+    /* set up args and a local for "&fp" */
+    /* (str sp, [sp, #-4]!  would be perfect here, but is discouraged) */
+    str     rFP, [sp, #-4]!             @ *--sp = fp
+    mov     ip, sp                      @ ip<- &fp
+    mov     r3, #0                      @ r3<- false
+    str     ip, [sp, #-4]!              @ *--sp = &fp
+    ldr     r1, [rGLUE, #offGlue_method] @ r1<- glue->method
+    mov     r0, r10                     @ r0<- self
+    ldr     r1, [r1, #offMethod_insns]  @ r1<- method->insns
+    mov     r2, r9                      @ r2<- exception
+    sub     r1, rPC, r1                 @ r1<- pc - method->insns
+    mov     r1, r1, asr #1              @ r1<- offset in code units
+
+    /* call, r0 gets catchRelPc (a code-unit offset) */
+    bl      dvmFindCatchBlock           @ call(self, relPc, exc, scan?, &fp)
+
+    /* fix earlier stack overflow if necessary; may trash rFP */
+    ldrb    r1, [r10, #offThread_stackOverflowed]
+    cmp     r1, #0                      @ did we overflow earlier?
+    beq     1f                          @ no, skip ahead
+    mov     rFP, r0                     @ save relPc result in rFP
+    mov     r0, r10                     @ r0<- self
+    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->curFrame and updated PC */
+    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- new save area
+    ldr     r1, [r1, #offStackSaveArea_method] @ r1<- new method
+    str     r1, [rGLUE, #offGlue_method]    @ glue->method = new method
+    ldr     r2, [r1, #offMethod_clazz]      @ r2<- method->clazz
+    ldr     r3, [r1, #offMethod_insns]      @ r3<- method->insns
+    ldr     r2, [r2, #offClassObject_pDvmDex] @ r2<- method->clazz->pDvmDex
+    add     rPC, r3, r0, asl #1             @ rPC<- method->insns + catchRelPc
+    str     r2, [rGLUE, #offGlue_methodClassDex] @ glue->pDvmDex = meth...
+
+    /* release the tracked alloc on the exception */
+    mov     r0, r9                      @ r0<- exception
+    mov     r1, r10                     @ r1<- self
+    bl      dvmReleaseTrackedAlloc      @ release the exception
+
+    /* restore the exception if the handler wants it */
+    FETCH_INST()                        @ load rINST from rPC
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    cmp     ip, #OP_MOVE_EXCEPTION      @ is it "move-exception"?
+    streq   r9, [r10, #offThread_exception] @ yes, restore the exception
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+.LnotCaughtLocally: @ r9=exception, r10=self
+    /* fix stack overflow if necessary */
+    ldrb    r1, [r10, #offThread_stackOverflowed]
+    cmp     r1, #0                      @ did we overflow earlier?
+    movne   r0, r10                     @ if yes: r0<- self
+    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, [rGLUE, #offGlue_method]
+    ldr     r1, [r0, #offMethod_insns]
+    sub     r1, rPC, r1
+    asr     r1, r1, #1
+    bl      dvmLineNumFromPC
+    str     r0, [sp, #-4]!
+    @ dvmGetMethodSourceFile(method)
+    ldr     r0, [rGLUE, #offGlue_method]
+    bl      dvmGetMethodSourceFile
+    str     r0, [sp, #-4]!
+    @ exception->clazz->descriptor
+    ldr     r3, [r9, #offObject_clazz]
+    ldr     r3, [r3, #offClassObject_descriptor]
+    @
+    ldr     r2, strExceptionNotCaughtLocally
+    ldr     r1, strLogTag
+    mov     r0, #3                      @ LOG_DEBUG
+    bl      __android_log_print
+#endif
+    str     r9, [r10, #offThread_exception] @ restore exception
+    mov     r0, r9                      @ r0<- exception
+    mov     r1, r10                     @ r1<- self
+    bl      dvmReleaseTrackedAlloc      @ release the exception
+    mov     r1, #0                      @ "want switch" = false
+    b       common_gotoBail             @ bail out
+
+
+    /*
+     * Exception handling, calls through "glue code".
+     */
+    .if     0
+.LexceptionOld:
+    SAVE_PC_FP_TO_GLUE()                @ export state
+    mov     r0, rGLUE                   @ arg to function
+    bl      dvmMterp_exceptionThrown
+    b       common_resumeAfterGlueCall
+    .endif
+
+
+/*
+ * After returning from a "glued" function, pull out the updated
+ * values and start executing at the next instruction.
+ */
+common_resumeAfterGlueCall:
+    LOAD_PC_FP_FROM_GLUE()              @ pull rPC and rFP out of glue
+    FETCH_INST()                        @ load rINST from rPC
+    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
+    GOTO_OPCODE(ip)                     @ jump to next instruction
+
+/*
+ * Invalid array index.
+ */
+common_errArrayIndex:
+    EXPORT_PC()
+    ldr     r0, strArrayIndexException
+    mov     r1, #0
+    bl      dvmThrowException
+    b       common_exceptionThrown
+
+/*
+ * Invalid array value.
+ */
+common_errArrayStore:
+    EXPORT_PC()
+    ldr     r0, strArrayStoreException
+    mov     r1, #0
+    bl      dvmThrowException
+    b       common_exceptionThrown
+
+/*
+ * Integer divide or mod by zero.
+ */
+common_errDivideByZero:
+    EXPORT_PC()
+    ldr     r0, strArithmeticException
+    ldr     r1, strDivideByZero
+    bl      dvmThrowException
+    b       common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ */
+common_errNegativeArraySize:
+    EXPORT_PC()
+    ldr     r0, strNegativeArraySizeException
+    mov     r1, #0
+    bl      dvmThrowException
+    b       common_exceptionThrown
+
+/*
+ * Invocation of a non-existent method.
+ */
+common_errNoSuchMethod:
+    EXPORT_PC()
+    ldr     r0, strNoSuchMethodError
+    mov     r1, #0
+    bl      dvmThrowException
+    b       common_exceptionThrown
+
+/*
+ * We encountered a null object when we weren't expecting one.  We
+ * export the PC, throw a NullPointerException, and goto the exception
+ * processing code.
+ */
+common_errNullObject:
+    EXPORT_PC()
+    ldr     r0, strNullPointerException
+    mov     r1, #0
+    bl      dvmThrowException
+    b       common_exceptionThrown
+
+/*
+ * For debugging, cause an immediate fault.  The source address will
+ * be in lr (use a bl instruction to jump here).
+ */
+common_abort:
+    ldr     pc, .LdeadFood
+.LdeadFood:
+    .word   0xdeadf00d
+
+/*
+ * Spit out a "we were here", preserving all registers.  (The attempt
+ * to save ip won't work, but we need to save an even number of
+ * registers for EABI 64-bit stack alignment.)
+ */
+    .macro  SQUEAK num
+common_squeak\num:
+    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    ldr     r0, strSqueak
+    mov     r1, #\num
+    bl      printf
+    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    bx      lr
+    .endm
+
+    SQUEAK  0
+    SQUEAK  1
+    SQUEAK  2
+    SQUEAK  3
+    SQUEAK  4
+    SQUEAK  5
+
+/*
+ * Spit out the number in r0, preserving registers.
+ */
+common_printNum:
+    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    mov     r1, r0
+    ldr     r0, strSqueak
+    bl      printf
+    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    bx      lr
+
+/*
+ * Print a newline, preserving registers.
+ */
+common_printNewline:
+    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    ldr     r0, strNewline
+    bl      printf
+    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    bx      lr
+
+    /*
+     * Print the 32-bit quantity in r0 as a hex value, preserving registers.
+     */
+common_printHex:
+    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    mov     r1, r0
+    ldr     r0, strPrintHex
+    bl      printf
+    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    bx      lr
+
+/*
+ * Print the 64-bit quantity in r0-r1, preserving registers.
+ */
+common_printLong:
+    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    mov     r3, r1
+    mov     r2, r0
+    ldr     r0, strPrintLong
+    bl      printf
+    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    bx      lr
+
+/*
+ * Print full method info.  Pass the Method* in r0.  Preserves regs.
+ */
+common_printMethod:
+    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    bl      dvmMterpPrintMethod
+    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    bx      lr
+
+/*
+ * Call a C helper function that dumps regs and possibly some
+ * additional info.  Requires the C function to be compiled in.
+ */
+    .if     0
+common_dumpRegs:
+    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    bl      dvmMterpDumpArmRegs
+    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
+    bx      lr
+    .endif
+
+#if 0
+/*
+ * Experiment on VFP mode.
+ *
+ * uint32_t setFPSCR(uint32_t val, uint32_t mask)
+ *
+ * Updates the bits specified by "mask", setting them to the values in "val".
+ */
+setFPSCR:
+    and     r0, r0, r1                  @ make sure no stray bits are set
+    fmrx    r2, fpscr                   @ get VFP reg
+    mvn     r1, r1                      @ bit-invert mask
+    and     r2, r2, r1                  @ clear masked bits
+    orr     r2, r2, r0                  @ set specified bits
+    fmxr    fpscr, r2                   @ set VFP reg
+    mov     r0, r2                      @ return new value
+    bx      lr
+
+    .align  2
+    .global dvmConfigureFP
+    .type   dvmConfigureFP, %function
+dvmConfigureFP:
+    stmfd   sp!, {ip, lr}
+    /* 0x03000000 sets DN/FZ */
+    /* 0x00009f00 clears the six exception enable flags */
+    bl      common_squeak0
+    mov     r0, #0x03000000             @ r0<- 0x03000000
+    add     r1, r0, #0x9f00             @ r1<- 0x03009f00
+    bl      setFPSCR
+    ldmfd   sp!, {ip, pc}
+#endif
+
+
+/*
+ * String references, must be close to the code that uses them.
+ */
+    .align  2
+strArithmeticException:
+    .word   .LstrArithmeticException
+strArrayIndexException:
+    .word   .LstrArrayIndexException
+strArrayStoreException:
+    .word   .LstrArrayStoreException
+strDivideByZero:
+    .word   .LstrDivideByZero
+strNegativeArraySizeException:
+    .word   .LstrNegativeArraySizeException
+strNoSuchMethodError:
+    .word   .LstrNoSuchMethodError
+strNullPointerException:
+    .word   .LstrNullPointerException
+
+strLogTag:
+    .word   .LstrLogTag
+strExceptionNotCaughtLocally:
+    .word   .LstrExceptionNotCaughtLocally
+
+strNewline:
+    .word   .LstrNewline
+strSqueak:
+    .word   .LstrSqueak
+strPrintHex:
+    .word   .LstrPrintHex
+strPrintLong:
+    .word   .LstrPrintLong
+
+/*
+ * Zero-terminated ASCII string data.
+ *
+ * On ARM we have two choices: do like gcc does, and LDR from a .word
+ * with the address, or use an ADR pseudo-op to get the address
+ * directly.  ADR saves 4 bytes and an indirection, but it's using a
+ * PC-relative addressing mode and hence has a limited range, which
+ * makes it not work well with mergeable string sections.
+ */
+    .section .rodata.str1.4,"aMS",%progbits,1
+
+.LstrBadEntryPoint:
+    .asciz  "Bad entry point %d\n"
+.LstrArithmeticException:
+    .asciz  "Ljava/lang/ArithmeticException;"
+.LstrArrayIndexException:
+    .asciz  "Ljava/lang/ArrayIndexOutOfBoundsException;"
+.LstrArrayStoreException:
+    .asciz  "Ljava/lang/ArrayStoreException;"
+.LstrClassCastException:
+    .asciz  "Ljava/lang/ClassCastException;"
+.LstrDivideByZero:
+    .asciz  "divide by zero"
+.LstrFilledNewArrayNotImpl:
+    .asciz  "filled-new-array only implemented for objects and 'int'"
+.LstrInternalError:
+    .asciz  "Ljava/lang/InternalError;"
+.LstrInstantiationError:
+    .asciz  "Ljava/lang/InstantiationError;"
+.LstrNegativeArraySizeException:
+    .asciz  "Ljava/lang/NegativeArraySizeException;"
+.LstrNoSuchMethodError:
+    .asciz  "Ljava/lang/NoSuchMethodError;"
+.LstrNullPointerException:
+    .asciz  "Ljava/lang/NullPointerException;"
+
+.LstrLogTag:
+    .asciz  "mterp"
+.LstrExceptionNotCaughtLocally:
+    .asciz  "Exception %s from %s:%d not caught locally\n"
+
+.LstrNewline:
+    .asciz  "\n"
+.LstrSqueak:
+    .asciz  "<%d>"
+.LstrPrintHex:
+    .asciz  "<0x%x>"
+.LstrPrintLong:
+    .asciz  "<%lld>"
+
+
diff --git a/vm/mterp/out/InterpAsm-armv7-a.S b/vm/mterp/out/InterpAsm-armv7-a.S
index 49c3d9e..2e48175 100644
--- a/vm/mterp/out/InterpAsm-armv7-a.S
+++ b/vm/mterp/out/InterpAsm-armv7-a.S
@@ -306,7 +306,7 @@
 
     /* set up "named" registers, figure out entry point */
     mov     rGLUE, r0                   @ set rGLUE
-    ldrb    r1, [r0, #offGlue_entryPoint]   @ InterpEntry enum is char
+    ldr     r1, [r0, #offGlue_entryPoint]   @ enum is 4 bytes in aapcs-EABI
     LOAD_PC_FP_FROM_GLUE()              @ load rPC and rFP from "glue"
     adr     rIBASE, dvmAsmInstructionStart  @ set rIBASE
     cmp     r1, #kInterpEntryInstr      @ usual case?
@@ -348,7 +348,7 @@
     cmp     rPC,r2
     bne     .Lno_singleStep             @ must have branched, don't resume
     mov     r1, #kInterpEntryInstr
-    strb    r1, [rGLUE, #offGlue_entryPoint]
+    str     r1, [rGLUE, #offGlue_entryPoint]
     ldr     rINST, .LdvmCompilerTemplate
     bx      r0                          @ re-enter the translation
 .LdvmCompilerTemplate:
@@ -9880,11 +9880,6 @@
     mov     r9, #0
     bl      common_periodicChecks
 
-#if defined(WITH_JIT)
-    mov     r2,#kJitTSelectAbort        @ abandon trace selection in progress
-    str     r2,[rGLUE,#offGlue_jitState]
-#endif
-
     ldr     r10, [rGLUE, #offGlue_self] @ r10<- glue->self
     ldr     r9, [r10, #offThread_exception] @ r9<- self->exception
     mov     r1, r10                     @ r1<- self
diff --git a/vm/mterp/out/InterpC-armv7-a-neon.c b/vm/mterp/out/InterpC-armv7-a-neon.c
new file mode 100644
index 0000000..0930f28
--- /dev/null
+++ b/vm/mterp/out/InterpC-armv7-a-neon.c
@@ -0,0 +1,1286 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'armv7-a-neon'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: c/header.c */
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* common includes */
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "mterp/Mterp.h"
+#include <math.h>                   // needed for fmod, fmodf
+#include "mterp/common/FindInterface.h"
+
+/*
+ * Configuration defines.  These affect the C implementations, i.e. the
+ * portable interpreter(s) and C stubs.
+ *
+ * Some defines are controlled by the Makefile, e.g.:
+ *   WITH_PROFILER
+ *   WITH_DEBUGGER
+ *   WITH_INSTR_CHECKS
+ *   WITH_TRACKREF_CHECKS
+ *   EASY_GDB
+ *   NDEBUG
+ *
+ * If THREADED_INTERP is not defined, we use a classic "while true / switch"
+ * interpreter.  If it is defined, then the tail end of each instruction
+ * handler fetches the next instruction and jumps directly to the handler.
+ * This increases the size of the "Std" interpreter by about 10%, but
+ * provides a speedup of about the same magnitude.
+ *
+ * There's a "hybrid" approach that uses a goto table instead of a switch
+ * statement, avoiding the "is the opcode in range" tests required for switch.
+ * The performance is close to the threaded version, and without the 10%
+ * size increase, but the benchmark results are off enough that it's not
+ * worth adding as a third option.
+ */
+#define THREADED_INTERP             /* threaded vs. while-loop interpreter */
+
+#ifdef WITH_INSTR_CHECKS            /* instruction-level paranoia (slow!) */
+# define CHECK_BRANCH_OFFSETS
+# define CHECK_REGISTER_INDICES
+#endif
+
+/*
+ * ARM EABI requires 64-bit alignment for access to 64-bit data types.  We
+ * can't just use pointers to copy 64-bit values out of our interpreted
+ * register set, because gcc will generate ldrd/strd.
+ *
+ * The __UNION version copies data in and out of a union.  The __MEMCPY
+ * version uses a memcpy() call to do the transfer; gcc is smart enough to
+ * not actually call memcpy().  The __UNION version is very bad on ARM;
+ * it only uses one more instruction than __MEMCPY, but for some reason
+ * gcc thinks it needs separate storage for every instance of the union.
+ * On top of that, it feels the need to zero them out at the start of the
+ * method.  Net result is we zero out ~700 bytes of stack space at the top
+ * of the interpreter using ARM STM instructions.
+ */
+#if defined(__ARM_EABI__)
+//# define NO_UNALIGN_64__UNION
+# define NO_UNALIGN_64__MEMCPY
+#endif
+
+//#define LOG_INSTR                   /* verbose debugging */
+/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
+
+/*
+ * Keep a tally of accesses to fields.  Currently only works if full DEX
+ * optimization is disabled.
+ */
+#ifdef PROFILE_FIELD_ACCESS
+# define UPDATE_FIELD_GET(_field) { (_field)->gets++; }
+# define UPDATE_FIELD_PUT(_field) { (_field)->puts++; }
+#else
+# define UPDATE_FIELD_GET(_field) ((void)0)
+# define UPDATE_FIELD_PUT(_field) ((void)0)
+#endif
+
+/*
+ * Export another copy of the PC on every instruction; this is largely
+ * redundant with EXPORT_PC and the debugger code.  This value can be
+ * compared against what we have stored on the stack with EXPORT_PC to
+ * help ensure that we aren't missing any export calls.
+ */
+#if WITH_EXTRA_GC_CHECKS > 1
+# define EXPORT_EXTRA_PC() (self->currentPc2 = pc)
+#else
+# define EXPORT_EXTRA_PC()
+#endif
+
+/*
+ * Adjust the program counter.  "_offset" is a signed int, in 16-bit units.
+ *
+ * Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
+ *
+ * We don't advance the program counter until we finish an instruction or
+ * branch, because we do want to have to unroll the PC if there's an
+ * exception.
+ */
+#ifdef CHECK_BRANCH_OFFSETS
+# define ADJUST_PC(_offset) do {                                            \
+        int myoff = _offset;        /* deref only once */                   \
+        if (pc + myoff < curMethod->insns ||                                \
+            pc + myoff >= curMethod->insns + dvmGetMethodInsnsSize(curMethod)) \
+        {                                                                   \
+            char* desc;                                                     \
+            desc = dexProtoCopyMethodDescriptor(&curMethod->prototype);     \
+            LOGE("Invalid branch %d at 0x%04x in %s.%s %s\n",               \
+                myoff, (int) (pc - curMethod->insns),                       \
+                curMethod->clazz->descriptor, curMethod->name, desc);       \
+            free(desc);                                                     \
+            dvmAbort();                                                     \
+        }                                                                   \
+        pc += myoff;                                                        \
+        EXPORT_EXTRA_PC();                                                  \
+    } while (false)
+#else
+# define ADJUST_PC(_offset) do {                                            \
+        pc += _offset;                                                      \
+        EXPORT_EXTRA_PC();                                                  \
+    } while (false)
+#endif
+
+/*
+ * If enabled, log instructions as we execute them.
+ */
+#ifdef LOG_INSTR
+# define ILOGD(...) ILOG(LOG_DEBUG, __VA_ARGS__)
+# define ILOGV(...) ILOG(LOG_VERBOSE, __VA_ARGS__)
+# define ILOG(_level, ...) do {                                             \
+        char debugStrBuf[128];                                              \
+        snprintf(debugStrBuf, sizeof(debugStrBuf), __VA_ARGS__);            \
+        if (curMethod != NULL)                                                 \
+            LOG(_level, LOG_TAG"i", "%-2d|%04x%s\n",                        \
+                self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
+        else                                                                \
+            LOG(_level, LOG_TAG"i", "%-2d|####%s\n",                        \
+                self->threadId, debugStrBuf);                               \
+    } while(false)
+void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly);
+# define DUMP_REGS(_meth, _frame, _inOnly) dvmDumpRegs(_meth, _frame, _inOnly)
+static const char kSpacing[] = "            ";
+#else
+# define ILOGD(...) ((void)0)
+# define ILOGV(...) ((void)0)
+# define DUMP_REGS(_meth, _frame, _inOnly) ((void)0)
+#endif
+
+/* get a long from an array of u4 */
+static inline s8 getLongFromArray(const u4* ptr, int idx)
+{
+#if defined(NO_UNALIGN_64__UNION)
+    union { s8 ll; u4 parts[2]; } conv;
+
+    ptr += idx;
+    conv.parts[0] = ptr[0];
+    conv.parts[1] = ptr[1];
+    return conv.ll;
+#elif defined(NO_UNALIGN_64__MEMCPY)
+    s8 val;
+    memcpy(&val, &ptr[idx], 8);
+    return val;
+#else
+    return *((s8*) &ptr[idx]);
+#endif
+}
+
+/* store a long into an array of u4 */
+static inline void putLongToArray(u4* ptr, int idx, s8 val)
+{
+#if defined(NO_UNALIGN_64__UNION)
+    union { s8 ll; u4 parts[2]; } conv;
+
+    ptr += idx;
+    conv.ll = val;
+    ptr[0] = conv.parts[0];
+    ptr[1] = conv.parts[1];
+#elif defined(NO_UNALIGN_64__MEMCPY)
+    memcpy(&ptr[idx], &val, 8);
+#else
+    *((s8*) &ptr[idx]) = val;
+#endif
+}
+
+/* get a double from an array of u4 */
+static inline double getDoubleFromArray(const u4* ptr, int idx)
+{
+#if defined(NO_UNALIGN_64__UNION)
+    union { double d; u4 parts[2]; } conv;
+
+    ptr += idx;
+    conv.parts[0] = ptr[0];
+    conv.parts[1] = ptr[1];
+    return conv.d;
+#elif defined(NO_UNALIGN_64__MEMCPY)
+    double dval;
+    memcpy(&dval, &ptr[idx], 8);
+    return dval;
+#else
+    return *((double*) &ptr[idx]);
+#endif
+}
+
+/* store a double into an array of u4 */
+static inline void putDoubleToArray(u4* ptr, int idx, double dval)
+{
+#if defined(NO_UNALIGN_64__UNION)
+    union { double d; u4 parts[2]; } conv;
+
+    ptr += idx;
+    conv.d = dval;
+    ptr[0] = conv.parts[0];
+    ptr[1] = conv.parts[1];
+#elif defined(NO_UNALIGN_64__MEMCPY)
+    memcpy(&ptr[idx], &dval, 8);
+#else
+    *((double*) &ptr[idx]) = dval;
+#endif
+}
+
+/*
+ * If enabled, validate the register number on every access.  Otherwise,
+ * just do an array access.
+ *
+ * Assumes the existence of "u4* fp".
+ *
+ * "_idx" may be referenced more than once.
+ */
+#ifdef CHECK_REGISTER_INDICES
+# define GET_REGISTER(_idx) \
+    ( (_idx) < curMethod->registersSize ? \
+        (fp[(_idx)]) : (assert(!"bad reg"),1969) )
+# define SET_REGISTER(_idx, _val) \
+    ( (_idx) < curMethod->registersSize ? \
+        (fp[(_idx)] = (u4)(_val)) : (assert(!"bad reg"),1969) )
+# define GET_REGISTER_AS_OBJECT(_idx)       ((Object *)GET_REGISTER(_idx))
+# define SET_REGISTER_AS_OBJECT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
+# define GET_REGISTER_INT(_idx) ((s4) GET_REGISTER(_idx))
+# define SET_REGISTER_INT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
+# define GET_REGISTER_WIDE(_idx) \
+    ( (_idx) < curMethod->registersSize-1 ? \
+        getLongFromArray(fp, (_idx)) : (assert(!"bad reg"),1969) )
+# define SET_REGISTER_WIDE(_idx, _val) \
+    ( (_idx) < curMethod->registersSize-1 ? \
+        putLongToArray(fp, (_idx), (_val)) : (assert(!"bad reg"),1969) )
+# define GET_REGISTER_FLOAT(_idx) \
+    ( (_idx) < curMethod->registersSize ? \
+        (*((float*) &fp[(_idx)])) : (assert(!"bad reg"),1969.0f) )
+# define SET_REGISTER_FLOAT(_idx, _val) \
+    ( (_idx) < curMethod->registersSize ? \
+        (*((float*) &fp[(_idx)]) = (_val)) : (assert(!"bad reg"),1969.0f) )
+# define GET_REGISTER_DOUBLE(_idx) \
+    ( (_idx) < curMethod->registersSize-1 ? \
+        getDoubleFromArray(fp, (_idx)) : (assert(!"bad reg"),1969.0) )
+# define SET_REGISTER_DOUBLE(_idx, _val) \
+    ( (_idx) < curMethod->registersSize-1 ? \
+        putDoubleToArray(fp, (_idx), (_val)) : (assert(!"bad reg"),1969.0) )
+#else
+# define GET_REGISTER(_idx)                 (fp[(_idx)])
+# define SET_REGISTER(_idx, _val)           (fp[(_idx)] = (_val))
+# define GET_REGISTER_AS_OBJECT(_idx)       ((Object*) fp[(_idx)])
+# define SET_REGISTER_AS_OBJECT(_idx, _val) (fp[(_idx)] = (u4)(_val))
+# define GET_REGISTER_INT(_idx)             ((s4)GET_REGISTER(_idx))
+# define SET_REGISTER_INT(_idx, _val)       SET_REGISTER(_idx, (s4)_val)
+# define GET_REGISTER_WIDE(_idx)            getLongFromArray(fp, (_idx))
+# define SET_REGISTER_WIDE(_idx, _val)      putLongToArray(fp, (_idx), (_val))
+# define GET_REGISTER_FLOAT(_idx)           (*((float*) &fp[(_idx)]))
+# define SET_REGISTER_FLOAT(_idx, _val)     (*((float*) &fp[(_idx)]) = (_val))
+# define GET_REGISTER_DOUBLE(_idx)          getDoubleFromArray(fp, (_idx))
+# define SET_REGISTER_DOUBLE(_idx, _val)    putDoubleToArray(fp, (_idx), (_val))
+#endif
+
+/*
+ * Get 16 bits from the specified offset of the program counter.  We always
+ * want to load 16 bits at a time from the instruction stream -- it's more
+ * efficient than 8 and won't have the alignment problems that 32 might.
+ *
+ * Assumes existence of "const u2* pc".
+ */
+#define FETCH(_offset)     (pc[(_offset)])
+
+/*
+ * Extract instruction byte from 16-bit fetch (_inst is a u2).
+ */
+#define INST_INST(_inst)    ((_inst) & 0xff)
+
+/*
+ * 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 dvmThrowException(), so that the exception stack
+ * trace can be generated correctly.  If we don't do this, the offset
+ * within the current method won't be shown correctly.  See the notes
+ * in Exception.c.
+ *
+ * This is also used to determine the address for precise GC.
+ *
+ * Assumes existence of "u4* fp" and "const u2* pc".
+ */
+#define EXPORT_PC()         (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
+
+/*
+ * Determine if we need to switch to a different interpreter.  "_current"
+ * is either INTERP_STD or INTERP_DBG.  It should be fixed for a given
+ * interpreter generation file, which should remove the outer conditional
+ * from the following.
+ *
+ * If we're building without debug and profiling support, we never switch.
+ */
+#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
+#if defined(WITH_JIT)
+# define NEED_INTERP_SWITCH(_current) (                                     \
+    (_current == INTERP_STD) ?                                              \
+        dvmJitDebuggerOrProfilerActive() : !dvmJitDebuggerOrProfilerActive() )
+#else
+# define NEED_INTERP_SWITCH(_current) (                                     \
+    (_current == INTERP_STD) ?                                              \
+        dvmDebuggerOrProfilerActive() : !dvmDebuggerOrProfilerActive() )
+#endif
+#else
+# define NEED_INTERP_SWITCH(_current) (false)
+#endif
+
+/*
+ * Check to see if "obj" is NULL.  If so, throw an exception.  Assumes the
+ * pc has already been exported to the stack.
+ *
+ * Perform additional checks on debug builds.
+ *
+ * Use this to check for NULL when the instruction handler calls into
+ * something that could throw an exception (so we have already called
+ * EXPORT_PC at the top).
+ */
+static inline bool checkForNull(Object* obj)
+{
+    if (obj == NULL) {
+        dvmThrowException("Ljava/lang/NullPointerException;", NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsValidObject(obj)) {
+        LOGE("Invalid object %p\n", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)\n", obj->clazz, obj);
+        dvmAbort();
+    }
+#endif
+    return true;
+}
+
+/*
+ * Check to see if "obj" is NULL.  If so, export the PC into the stack
+ * frame and throw an exception.
+ *
+ * Perform additional checks on debug builds.
+ *
+ * Use this to check for NULL when the instruction handler doesn't do
+ * anything else that can throw an exception.
+ */
+static inline bool checkForNullExportPC(Object* obj, u4* fp, const u2* pc)
+{
+    if (obj == NULL) {
+        EXPORT_PC();
+        dvmThrowException("Ljava/lang/NullPointerException;", NULL);
+        return false;
+    }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+    if (!dvmIsValidObject(obj)) {
+        LOGE("Invalid object %p\n", obj);
+        dvmAbort();
+    }
+#endif
+#ifndef NDEBUG
+    if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+        /* probable heap corruption */
+        LOGE("Invalid object class %p (in %p)\n", obj->clazz, obj);
+        dvmAbort();
+    }
+#endif
+    return true;
+}
+
+/* File: cstubs/stubdefs.c */
+/* this is a standard (no debug support) interpreter */
+#define INTERP_TYPE INTERP_STD
+#define CHECK_DEBUG_AND_PROF() ((void)0)
+# define CHECK_TRACKED_REFS() ((void)0)
+#if defined(WITH_JIT)
+#define CHECK_JIT() (0)
+#define ABORT_JIT_TSELECT() ((void)0)
+#endif
+
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...)                                      \
+    void dvmMterp_##_target(MterpGlue* glue, ## __VA_ARGS__);
+
+#define GOTO_TARGET(_target, ...)                                           \
+    void dvmMterp_##_target(MterpGlue* glue, ## __VA_ARGS__) {              \
+        u2 ref, vsrc1, vsrc2, vdst;                                         \
+        u2 inst = FETCH(0);                                                 \
+        const Method* methodToCall;                                         \
+        StackSaveArea* debugSaveArea;
+
+#define GOTO_TARGET_END }
+
+/*
+ * Redefine what used to be local variable accesses into MterpGlue struct
+ * references.  (These are undefined down in "footer.c".)
+ */
+#define retval                  glue->retval
+#define pc                      glue->pc
+#define fp                      glue->fp
+#define curMethod               glue->method
+#define methodClassDex          glue->methodClassDex
+#define self                    glue->self
+#define debugTrackedRefStart    glue->debugTrackedRefStart
+
+/* ugh */
+#define STUB_HACK(x) x
+
+
+/*
+ * Opcode handler framing macros.  Here, each opcode is a separate function
+ * that takes a "glue" argument and returns void.  We can't declare
+ * these "static" because they may be called from an assembly stub.
+ */
+#define HANDLE_OPCODE(_op)                                                  \
+    void dvmMterp_##_op(MterpGlue* glue) {                                  \
+        u2 ref, vsrc1, vsrc2, vdst;                                         \
+        u2 inst = FETCH(0);
+
+#define OP_END }
+
+/*
+ * Like the "portable" FINISH, but don't reload "inst", and return to caller
+ * when done.
+ */
+#define FINISH(_offset) {                                                   \
+        ADJUST_PC(_offset);                                                 \
+        CHECK_DEBUG_AND_PROF();                                             \
+        CHECK_TRACKED_REFS();                                               \
+        return;                                                             \
+    }
+
+
+/*
+ * The "goto label" statements turn into function calls followed by
+ * return statements.  Some of the functions take arguments, which in the
+ * portable interpreter are handled by assigning values to globals.
+ */
+
+#define GOTO_exceptionThrown()                                              \
+    do {                                                                    \
+        dvmMterp_exceptionThrown(glue);                                     \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_returnFromMethod()                                             \
+    do {                                                                    \
+        dvmMterp_returnFromMethod(glue);                                    \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invoke(_target, _methodCallRange)                              \
+    do {                                                                    \
+        dvmMterp_##_target(glue, _methodCallRange);                         \
+        return;                                                             \
+    } while(false)
+
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst)   \
+    do {                                                                    \
+        dvmMterp_invokeMethod(glue, _methodCallRange, _methodToCall,        \
+            _vsrc1, _vdst);                                                 \
+        return;                                                             \
+    } while(false)
+
+/*
+ * As a special case, "goto bail" turns into a longjmp.  Use "bail_switch"
+ * if we need to switch to the other interpreter upon our return.
+ */
+#define GOTO_bail()                                                         \
+    dvmMterpStdBail(glue, false);
+#define GOTO_bail_switch()                                                  \
+    dvmMterpStdBail(glue, true);
+
+/*
+ * Periodically check for thread suspension.
+ *
+ * While we're at it, see if a debugger has attached or the profiler has
+ * started.  If so, switch to a different "goto" table.
+ */
+#define PERIODIC_CHECKS(_entryPoint, _pcadj) {                              \
+        if (dvmCheckSuspendQuick(self)) {                                   \
+            EXPORT_PC();  /* need for precise GC */                         \
+            dvmCheckSuspendPending(self);                                   \
+        }                                                                   \
+        if (NEED_INTERP_SWITCH(INTERP_TYPE)) {                              \
+            ADJUST_PC(_pcadj);                                              \
+            glue->entryPoint = _entryPoint;                                 \
+            LOGVV("threadid=%d: switch to STD ep=%d adj=%d\n",              \
+                self->threadId, (_entryPoint), (_pcadj));                   \
+            GOTO_bail_switch();                                             \
+        }                                                                   \
+    }
+
+/* File: c/opcommon.c */
+/* forward declarations of goto targets */
+GOTO_TARGET_DECL(filledNewArray, bool methodCallRange);
+GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange);
+GOTO_TARGET_DECL(invokeSuper, bool methodCallRange);
+GOTO_TARGET_DECL(invokeInterface, bool methodCallRange);
+GOTO_TARGET_DECL(invokeDirect, bool methodCallRange);
+GOTO_TARGET_DECL(invokeStatic, bool methodCallRange);
+GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange);
+GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange);
+GOTO_TARGET_DECL(invokeMethod, bool methodCallRange, const Method* methodToCall,
+    u2 count, u2 regs);
+GOTO_TARGET_DECL(returnFromMethod);
+GOTO_TARGET_DECL(exceptionThrown);
+
+/*
+ * ===========================================================================
+ *
+ * What follows are opcode definitions shared between multiple opcodes with
+ * minor substitutions handled by the C pre-processor.  These should probably
+ * use the mterp substitution mechanism instead, with the code here moved
+ * into common fragment files (like the asm "binop.S"), although it's hard
+ * to give up the C preprocessor in favor of the much simpler text subst.
+ *
+ * ===========================================================================
+ */
+
+#define HANDLE_NUMCONV(_opcode, _opname, _fromtype, _totype)                \
+    HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);                                               \
+        ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1);                       \
+        SET_REGISTER##_totype(vdst,                                         \
+            GET_REGISTER##_fromtype(vsrc1));                                \
+        FINISH(1);
+
+#define HANDLE_FLOAT_TO_INT(_opcode, _opname, _fromvtype, _fromrtype,       \
+        _tovtype, _tortype)                                                 \
+    HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
+    {                                                                       \
+        /* spec defines specific handling for +/- inf and NaN values */     \
+        _fromvtype val;                                                     \
+        _tovtype intMin, intMax, result;                                    \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);                                               \
+        ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1);                       \
+        val = GET_REGISTER##_fromrtype(vsrc1);                              \
+        intMin = (_tovtype) 1 << (sizeof(_tovtype) * 8 -1);                 \
+        intMax = ~intMin;                                                   \
+        result = (_tovtype) val;                                            \
+        if (val >= intMax)          /* +inf */                              \
+            result = intMax;                                                \
+        else if (val <= intMin)     /* -inf */                              \
+            result = intMin;                                                \
+        else if (val != val)        /* NaN */                               \
+            result = 0;                                                     \
+        else                                                                \
+            result = (_tovtype) val;                                        \
+        SET_REGISTER##_tortype(vdst, result);                               \
+    }                                                                       \
+    FINISH(1);
+
+#define HANDLE_INT_TO_SMALL(_opcode, _opname, _type)                        \
+    HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);                                               \
+        ILOGV("|int-to-%s v%d,v%d", (_opname), vdst, vsrc1);                \
+        SET_REGISTER(vdst, (_type) GET_REGISTER(vsrc1));                    \
+        FINISH(1);
+
+/* NOTE: the comparison result is always a signed 4-byte integer */
+#define HANDLE_OP_CMPX(_opcode, _opname, _varType, _type, _nanVal)          \
+    HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
+    {                                                                       \
+        int result;                                                         \
+        u2 regs;                                                            \
+        _varType val1, val2;                                                \
+        vdst = INST_AA(inst);                                               \
+        regs = FETCH(1);                                                    \
+        vsrc1 = regs & 0xff;                                                \
+        vsrc2 = regs >> 8;                                                  \
+        ILOGV("|cmp%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);         \
+        val1 = GET_REGISTER##_type(vsrc1);                                  \
+        val2 = GET_REGISTER##_type(vsrc2);                                  \
+        if (val1 == val2)                                                   \
+            result = 0;                                                     \
+        else if (val1 < val2)                                               \
+            result = -1;                                                    \
+        else if (val1 > val2)                                               \
+            result = 1;                                                     \
+        else                                                                \
+            result = (_nanVal);                                             \
+        ILOGV("+ result=%d\n", result);                                     \
+        SET_REGISTER(vdst, result);                                         \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_OP_IF_XX(_opcode, _opname, _cmp)                             \
+    HANDLE_OPCODE(_opcode /*vA, vB, +CCCC*/)                                \
+        vsrc1 = INST_A(inst);                                               \
+        vsrc2 = INST_B(inst);                                               \
+        if ((s4) GET_REGISTER(vsrc1) _cmp (s4) GET_REGISTER(vsrc2)) {       \
+            int branchOffset = (s2)FETCH(1);    /* sign-extended */         \
+            ILOGV("|if-%s v%d,v%d,+0x%04x", (_opname), vsrc1, vsrc2,        \
+                branchOffset);                                              \
+            ILOGV("> branch taken");                                        \
+            if (branchOffset < 0)                                           \
+                PERIODIC_CHECKS(kInterpEntryInstr, branchOffset);           \
+            FINISH(branchOffset);                                           \
+        } else {                                                            \
+            ILOGV("|if-%s v%d,v%d,-", (_opname), vsrc1, vsrc2);             \
+            FINISH(2);                                                      \
+        }
+
+#define HANDLE_OP_IF_XXZ(_opcode, _opname, _cmp)                            \
+    HANDLE_OPCODE(_opcode /*vAA, +BBBB*/)                                   \
+        vsrc1 = INST_AA(inst);                                              \
+        if ((s4) GET_REGISTER(vsrc1) _cmp 0) {                              \
+            int branchOffset = (s2)FETCH(1);    /* sign-extended */         \
+            ILOGV("|if-%s v%d,+0x%04x", (_opname), vsrc1, branchOffset);    \
+            ILOGV("> branch taken");                                        \
+            if (branchOffset < 0)                                           \
+                PERIODIC_CHECKS(kInterpEntryInstr, branchOffset);           \
+            FINISH(branchOffset);                                           \
+        } else {                                                            \
+            ILOGV("|if-%s v%d,-", (_opname), vsrc1);                        \
+            FINISH(2);                                                      \
+        }
+
+#define HANDLE_UNOP(_opcode, _opname, _pfx, _sfx, _type)                    \
+    HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);                                               \
+        ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1);                       \
+        SET_REGISTER##_type(vdst, _pfx GET_REGISTER##_type(vsrc1) _sfx);    \
+        FINISH(1);
+
+#define HANDLE_OP_X_INT(_opcode, _opname, _op, _chkdiv)                     \
+    HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
+    {                                                                       \
+        u2 srcRegs;                                                         \
+        vdst = INST_AA(inst);                                               \
+        srcRegs = FETCH(1);                                                 \
+        vsrc1 = srcRegs & 0xff;                                             \
+        vsrc2 = srcRegs >> 8;                                               \
+        ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1);                   \
+        if (_chkdiv != 0) {                                                 \
+            s4 firstVal, secondVal, result;                                 \
+            firstVal = GET_REGISTER(vsrc1);                                 \
+            secondVal = GET_REGISTER(vsrc2);                                \
+            if (secondVal == 0) {                                           \
+                EXPORT_PC();                                                \
+                dvmThrowException("Ljava/lang/ArithmeticException;",        \
+                    "divide by zero");                                      \
+                GOTO_exceptionThrown();                                     \
+            }                                                               \
+            if ((u4)firstVal == 0x80000000 && secondVal == -1) {            \
+                if (_chkdiv == 1)                                           \
+                    result = firstVal;  /* division */                      \
+                else                                                        \
+                    result = 0;         /* remainder */                     \
+            } else {                                                        \
+                result = firstVal _op secondVal;                            \
+            }                                                               \
+            SET_REGISTER(vdst, result);                                     \
+        } else {                                                            \
+            /* non-div/rem case */                                          \
+            SET_REGISTER(vdst,                                              \
+                (s4) GET_REGISTER(vsrc1) _op (s4) GET_REGISTER(vsrc2));     \
+        }                                                                   \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_OP_SHX_INT(_opcode, _opname, _cast, _op)                     \
+    HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
+    {                                                                       \
+        u2 srcRegs;                                                         \
+        vdst = INST_AA(inst);                                               \
+        srcRegs = FETCH(1);                                                 \
+        vsrc1 = srcRegs & 0xff;                                             \
+        vsrc2 = srcRegs >> 8;                                               \
+        ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1);                   \
+        SET_REGISTER(vdst,                                                  \
+            _cast GET_REGISTER(vsrc1) _op (GET_REGISTER(vsrc2) & 0x1f));    \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_OP_X_INT_LIT16(_opcode, _opname, _op, _chkdiv)               \
+    HANDLE_OPCODE(_opcode /*vA, vB, #+CCCC*/)                               \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);                                               \
+        vsrc2 = FETCH(1);                                                   \
+        ILOGV("|%s-int/lit16 v%d,v%d,#+0x%04x",                             \
+            (_opname), vdst, vsrc1, vsrc2);                                 \
+        if (_chkdiv != 0) {                                                 \
+            s4 firstVal, result;                                            \
+            firstVal = GET_REGISTER(vsrc1);                                 \
+            if ((s2) vsrc2 == 0) {                                          \
+                EXPORT_PC();                                                \
+                dvmThrowException("Ljava/lang/ArithmeticException;",        \
+                    "divide by zero");                                      \
+                GOTO_exceptionThrown();                                      \
+            }                                                               \
+            if ((u4)firstVal == 0x80000000 && ((s2) vsrc2) == -1) {         \
+                /* won't generate /lit16 instr for this; check anyway */    \
+                if (_chkdiv == 1)                                           \
+                    result = firstVal;  /* division */                      \
+                else                                                        \
+                    result = 0;         /* remainder */                     \
+            } else {                                                        \
+                result = firstVal _op (s2) vsrc2;                           \
+            }                                                               \
+            SET_REGISTER(vdst, result);                                     \
+        } else {                                                            \
+            /* non-div/rem case */                                          \
+            SET_REGISTER(vdst, GET_REGISTER(vsrc1) _op (s2) vsrc2);         \
+        }                                                                   \
+        FINISH(2);
+
+#define HANDLE_OP_X_INT_LIT8(_opcode, _opname, _op, _chkdiv)                \
+    HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/)                               \
+    {                                                                       \
+        u2 litInfo;                                                         \
+        vdst = INST_AA(inst);                                               \
+        litInfo = FETCH(1);                                                 \
+        vsrc1 = litInfo & 0xff;                                             \
+        vsrc2 = litInfo >> 8;       /* constant */                          \
+        ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x",                              \
+            (_opname), vdst, vsrc1, vsrc2);                                 \
+        if (_chkdiv != 0) {                                                 \
+            s4 firstVal, result;                                            \
+            firstVal = GET_REGISTER(vsrc1);                                 \
+            if ((s1) vsrc2 == 0) {                                          \
+                EXPORT_PC();                                                \
+                dvmThrowException("Ljava/lang/ArithmeticException;",        \
+                    "divide by zero");                                      \
+                GOTO_exceptionThrown();                                     \
+            }                                                               \
+            if ((u4)firstVal == 0x80000000 && ((s1) vsrc2) == -1) {         \
+                if (_chkdiv == 1)                                           \
+                    result = firstVal;  /* division */                      \
+                else                                                        \
+                    result = 0;         /* remainder */                     \
+            } else {                                                        \
+                result = firstVal _op ((s1) vsrc2);                         \
+            }                                                               \
+            SET_REGISTER(vdst, result);                                     \
+        } else {                                                            \
+            SET_REGISTER(vdst,                                              \
+                (s4) GET_REGISTER(vsrc1) _op (s1) vsrc2);                   \
+        }                                                                   \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_OP_SHX_INT_LIT8(_opcode, _opname, _cast, _op)                \
+    HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/)                               \
+    {                                                                       \
+        u2 litInfo;                                                         \
+        vdst = INST_AA(inst);                                               \
+        litInfo = FETCH(1);                                                 \
+        vsrc1 = litInfo & 0xff;                                             \
+        vsrc2 = litInfo >> 8;       /* constant */                          \
+        ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x",                              \
+            (_opname), vdst, vsrc1, vsrc2);                                 \
+        SET_REGISTER(vdst,                                                  \
+            _cast GET_REGISTER(vsrc1) _op (vsrc2 & 0x1f));                  \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_OP_X_INT_2ADDR(_opcode, _opname, _op, _chkdiv)               \
+    HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);                                               \
+        ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1);             \
+        if (_chkdiv != 0) {                                                 \
+            s4 firstVal, secondVal, result;                                 \
+            firstVal = GET_REGISTER(vdst);                                  \
+            secondVal = GET_REGISTER(vsrc1);                                \
+            if (secondVal == 0) {                                           \
+                EXPORT_PC();                                                \
+                dvmThrowException("Ljava/lang/ArithmeticException;",        \
+                    "divide by zero");                                      \
+                GOTO_exceptionThrown();                                     \
+            }                                                               \
+            if ((u4)firstVal == 0x80000000 && secondVal == -1) {            \
+                if (_chkdiv == 1)                                           \
+                    result = firstVal;  /* division */                      \
+                else                                                        \
+                    result = 0;         /* remainder */                     \
+            } else {                                                        \
+                result = firstVal _op secondVal;                            \
+            }                                                               \
+            SET_REGISTER(vdst, result);                                     \
+        } else {                                                            \
+            SET_REGISTER(vdst,                                              \
+                (s4) GET_REGISTER(vdst) _op (s4) GET_REGISTER(vsrc1));      \
+        }                                                                   \
+        FINISH(1);
+
+#define HANDLE_OP_SHX_INT_2ADDR(_opcode, _opname, _cast, _op)               \
+    HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);                                               \
+        ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1);             \
+        SET_REGISTER(vdst,                                                  \
+            _cast GET_REGISTER(vdst) _op (GET_REGISTER(vsrc1) & 0x1f));     \
+        FINISH(1);
+
+#define HANDLE_OP_X_LONG(_opcode, _opname, _op, _chkdiv)                    \
+    HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
+    {                                                                       \
+        u2 srcRegs;                                                         \
+        vdst = INST_AA(inst);                                               \
+        srcRegs = FETCH(1);                                                 \
+        vsrc1 = srcRegs & 0xff;                                             \
+        vsrc2 = srcRegs >> 8;                                               \
+        ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);       \
+        if (_chkdiv != 0) {                                                 \
+            s8 firstVal, secondVal, result;                                 \
+            firstVal = GET_REGISTER_WIDE(vsrc1);                            \
+            secondVal = GET_REGISTER_WIDE(vsrc2);                           \
+            if (secondVal == 0LL) {                                         \
+                EXPORT_PC();                                                \
+                dvmThrowException("Ljava/lang/ArithmeticException;",        \
+                    "divide by zero");                                      \
+                GOTO_exceptionThrown();                                     \
+            }                                                               \
+            if ((u8)firstVal == 0x8000000000000000ULL &&                    \
+                secondVal == -1LL)                                          \
+            {                                                               \
+                if (_chkdiv == 1)                                           \
+                    result = firstVal;  /* division */                      \
+                else                                                        \
+                    result = 0;         /* remainder */                     \
+            } else {                                                        \
+                result = firstVal _op secondVal;                            \
+            }                                                               \
+            SET_REGISTER_WIDE(vdst, result);                                \
+        } else {                                                            \
+            SET_REGISTER_WIDE(vdst,                                         \
+                (s8) GET_REGISTER_WIDE(vsrc1) _op (s8) GET_REGISTER_WIDE(vsrc2)); \
+        }                                                                   \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_OP_SHX_LONG(_opcode, _opname, _cast, _op)                    \
+    HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
+    {                                                                       \
+        u2 srcRegs;                                                         \
+        vdst = INST_AA(inst);                                               \
+        srcRegs = FETCH(1);                                                 \
+        vsrc1 = srcRegs & 0xff;                                             \
+        vsrc2 = srcRegs >> 8;                                               \
+        ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);       \
+        SET_REGISTER_WIDE(vdst,                                             \
+            _cast GET_REGISTER_WIDE(vsrc1) _op (GET_REGISTER(vsrc2) & 0x3f)); \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_OP_X_LONG_2ADDR(_opcode, _opname, _op, _chkdiv)              \
+    HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);                                               \
+        ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1);            \
+        if (_chkdiv != 0) {                                                 \
+            s8 firstVal, secondVal, result;                                 \
+            firstVal = GET_REGISTER_WIDE(vdst);                             \
+            secondVal = GET_REGISTER_WIDE(vsrc1);                           \
+            if (secondVal == 0LL) {                                         \
+                EXPORT_PC();                                                \
+                dvmThrowException("Ljava/lang/ArithmeticException;",        \
+                    "divide by zero");                                      \
+                GOTO_exceptionThrown();                                     \
+            }                                                               \
+            if ((u8)firstVal == 0x8000000000000000ULL &&                    \
+                secondVal == -1LL)                                          \
+            {                                                               \
+                if (_chkdiv == 1)                                           \
+                    result = firstVal;  /* division */                      \
+                else                                                        \
+                    result = 0;         /* remainder */                     \
+            } else {                                                        \
+                result = firstVal _op secondVal;                            \
+            }                                                               \
+            SET_REGISTER_WIDE(vdst, result);                                \
+        } else {                                                            \
+            SET_REGISTER_WIDE(vdst,                                         \
+                (s8) GET_REGISTER_WIDE(vdst) _op (s8)GET_REGISTER_WIDE(vsrc1));\
+        }                                                                   \
+        FINISH(1);
+
+#define HANDLE_OP_SHX_LONG_2ADDR(_opcode, _opname, _cast, _op)              \
+    HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);                                               \
+        ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1);            \
+        SET_REGISTER_WIDE(vdst,                                             \
+            _cast GET_REGISTER_WIDE(vdst) _op (GET_REGISTER(vsrc1) & 0x3f)); \
+        FINISH(1);
+
+#define HANDLE_OP_X_FLOAT(_opcode, _opname, _op)                            \
+    HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
+    {                                                                       \
+        u2 srcRegs;                                                         \
+        vdst = INST_AA(inst);                                               \
+        srcRegs = FETCH(1);                                                 \
+        vsrc1 = srcRegs & 0xff;                                             \
+        vsrc2 = srcRegs >> 8;                                               \
+        ILOGV("|%s-float v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);      \
+        SET_REGISTER_FLOAT(vdst,                                            \
+            GET_REGISTER_FLOAT(vsrc1) _op GET_REGISTER_FLOAT(vsrc2));       \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_OP_X_DOUBLE(_opcode, _opname, _op)                           \
+    HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
+    {                                                                       \
+        u2 srcRegs;                                                         \
+        vdst = INST_AA(inst);                                               \
+        srcRegs = FETCH(1);                                                 \
+        vsrc1 = srcRegs & 0xff;                                             \
+        vsrc2 = srcRegs >> 8;                                               \
+        ILOGV("|%s-double v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);     \
+        SET_REGISTER_DOUBLE(vdst,                                           \
+            GET_REGISTER_DOUBLE(vsrc1) _op GET_REGISTER_DOUBLE(vsrc2));     \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_OP_X_FLOAT_2ADDR(_opcode, _opname, _op)                      \
+    HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);                                               \
+        ILOGV("|%s-float-2addr v%d,v%d", (_opname), vdst, vsrc1);           \
+        SET_REGISTER_FLOAT(vdst,                                            \
+            GET_REGISTER_FLOAT(vdst) _op GET_REGISTER_FLOAT(vsrc1));        \
+        FINISH(1);
+
+#define HANDLE_OP_X_DOUBLE_2ADDR(_opcode, _opname, _op)                     \
+    HANDLE_OPCODE(_opcode /*vA, vB*/)                                       \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);                                               \
+        ILOGV("|%s-double-2addr v%d,v%d", (_opname), vdst, vsrc1);          \
+        SET_REGISTER_DOUBLE(vdst,                                           \
+            GET_REGISTER_DOUBLE(vdst) _op GET_REGISTER_DOUBLE(vsrc1));      \
+        FINISH(1);
+
+#define HANDLE_OP_AGET(_opcode, _opname, _type, _regsize)                   \
+    HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
+    {                                                                       \
+        ArrayObject* arrayObj;                                              \
+        u2 arrayInfo;                                                       \
+        EXPORT_PC();                                                        \
+        vdst = INST_AA(inst);                                               \
+        arrayInfo = FETCH(1);                                               \
+        vsrc1 = arrayInfo & 0xff;    /* array ptr */                        \
+        vsrc2 = arrayInfo >> 8;      /* index */                            \
+        ILOGV("|aget%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);        \
+        arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);                      \
+        if (!checkForNull((Object*) arrayObj))                              \
+            GOTO_exceptionThrown();                                         \
+        if (GET_REGISTER(vsrc2) >= arrayObj->length) {                      \
+            LOGV("Invalid array access: %p %d (len=%d)\n",                  \
+                arrayObj, vsrc2, arrayObj->length);                         \
+            dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
+                NULL);                                                      \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst,                                        \
+            ((_type*) arrayObj->contents)[GET_REGISTER(vsrc2)]);            \
+        ILOGV("+ AGET[%d]=0x%x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));  \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_OP_APUT(_opcode, _opname, _type, _regsize)                   \
+    HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/)                                \
+    {                                                                       \
+        ArrayObject* arrayObj;                                              \
+        u2 arrayInfo;                                                       \
+        EXPORT_PC();                                                        \
+        vdst = INST_AA(inst);       /* AA: source value */                  \
+        arrayInfo = FETCH(1);                                               \
+        vsrc1 = arrayInfo & 0xff;   /* BB: array ptr */                     \
+        vsrc2 = arrayInfo >> 8;     /* CC: index */                         \
+        ILOGV("|aput%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2);        \
+        arrayObj = (ArrayObject*) GET_REGISTER(vsrc1);                      \
+        if (!checkForNull((Object*) arrayObj))                              \
+            GOTO_exceptionThrown();                                         \
+        if (GET_REGISTER(vsrc2) >= arrayObj->length) {                      \
+            dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
+                NULL);                                                      \
+            GOTO_exceptionThrown();                                         \
+        }                                                                   \
+        ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
+        ((_type*) arrayObj->contents)[GET_REGISTER(vsrc2)] =                \
+            GET_REGISTER##_regsize(vdst);                                   \
+    }                                                                       \
+    FINISH(2);
+
+/*
+ * It's possible to get a bad value out of a field with sub-32-bit stores
+ * because the -quick versions always operate on 32 bits.  Consider:
+ *   short foo = -1  (sets a 32-bit register to 0xffffffff)
+ *   iput-quick foo  (writes all 32 bits to the field)
+ *   short bar = 1   (sets a 32-bit register to 0x00000001)
+ *   iput-short      (writes the low 16 bits to the field)
+ *   iget-quick foo  (reads all 32 bits from the field, yielding 0xffff0001)
+ * This can only happen when optimized and non-optimized code has interleaved
+ * access to the same field.  This is unlikely but possible.
+ *
+ * The easiest way to fix this is to always read/write 32 bits at a time.  On
+ * a device with a 16-bit data bus this is sub-optimal.  (The alternative
+ * approach is to have sub-int versions of iget-quick, but now we're wasting
+ * Dalvik instruction space and making it less likely that handler code will
+ * already be in the CPU i-cache.)
+ */
+#define HANDLE_IGET_X(_opcode, _opname, _ftype, _regsize)                   \
+    HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);   /* object ptr */                            \
+        ref = FETCH(1);         /* field ref */                             \
+        ILOGV("|iget%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
+        obj = (Object*) GET_REGISTER(vsrc1);                                \
+        if (!checkForNull(obj))                                             \
+            GOTO_exceptionThrown();                                         \
+        ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref);  \
+        if (ifield == NULL) {                                               \
+            ifield = dvmResolveInstField(curMethod->clazz, ref);            \
+            if (ifield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst,                                        \
+            dvmGetField##_ftype(obj, ifield->byteOffset));                  \
+        ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name,                   \
+            (u8) GET_REGISTER##_regsize(vdst));                             \
+        UPDATE_FIELD_GET(&ifield->field);                                   \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IGET_X_QUICK(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
+    {                                                                       \
+        Object* obj;                                                        \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);   /* object ptr */                            \
+        ref = FETCH(1);         /* field offset */                          \
+        ILOGV("|iget%s-quick v%d,v%d,field@+%u",                            \
+            (_opname), vdst, vsrc1, ref);                                   \
+        obj = (Object*) GET_REGISTER(vsrc1);                                \
+        if (!checkForNullExportPC(obj, fp, pc))                             \
+            GOTO_exceptionThrown();                                         \
+        SET_REGISTER##_regsize(vdst, dvmGetField##_ftype(obj, ref));        \
+        ILOGV("+ IGETQ %d=0x%08llx", ref,                                   \
+            (u8) GET_REGISTER##_regsize(vdst));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IPUT_X(_opcode, _opname, _ftype, _regsize)                   \
+    HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
+    {                                                                       \
+        InstField* ifield;                                                  \
+        Object* obj;                                                        \
+        EXPORT_PC();                                                        \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);   /* object ptr */                            \
+        ref = FETCH(1);         /* field ref */                             \
+        ILOGV("|iput%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
+        obj = (Object*) GET_REGISTER(vsrc1);                                \
+        if (!checkForNull(obj))                                             \
+            GOTO_exceptionThrown();                                         \
+        ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref);  \
+        if (ifield == NULL) {                                               \
+            ifield = dvmResolveInstField(curMethod->clazz, ref);            \
+            if (ifield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+        }                                                                   \
+        dvmSetField##_ftype(obj, ifield->byteOffset,                        \
+            GET_REGISTER##_regsize(vdst));                                  \
+        ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name,                   \
+            (u8) GET_REGISTER##_regsize(vdst));                             \
+        UPDATE_FIELD_PUT(&ifield->field);                                   \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_IPUT_X_QUICK(_opcode, _opname, _ftype, _regsize)             \
+    HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/)                           \
+    {                                                                       \
+        Object* obj;                                                        \
+        vdst = INST_A(inst);                                                \
+        vsrc1 = INST_B(inst);   /* object ptr */                            \
+        ref = FETCH(1);         /* field offset */                          \
+        ILOGV("|iput%s-quick v%d,v%d,field@0x%04x",                         \
+            (_opname), vdst, vsrc1, ref);                                   \
+        obj = (Object*) GET_REGISTER(vsrc1);                                \
+        if (!checkForNullExportPC(obj, fp, pc))                             \
+            GOTO_exceptionThrown();                                         \
+        dvmSetField##_ftype(obj, ref, GET_REGISTER##_regsize(vdst));        \
+        ILOGV("+ IPUTQ %d=0x%08llx", ref,                                   \
+            (u8) GET_REGISTER##_regsize(vdst));                             \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize)                   \
+    HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/)                              \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        vdst = INST_AA(inst);                                               \
+        ref = FETCH(1);         /* field ref */                             \
+        ILOGV("|sget%s v%d,sfield@0x%04x", (_opname), vdst, ref);           \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+        }                                                                   \
+        SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield));    \
+        ILOGV("+ SGET '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+        UPDATE_FIELD_GET(&sfield->field);                                   \
+    }                                                                       \
+    FINISH(2);
+
+#define HANDLE_SPUT_X(_opcode, _opname, _ftype, _regsize)                   \
+    HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/)                              \
+    {                                                                       \
+        StaticField* sfield;                                                \
+        vdst = INST_AA(inst);                                               \
+        ref = FETCH(1);         /* field ref */                             \
+        ILOGV("|sput%s v%d,sfield@0x%04x", (_opname), vdst, ref);           \
+        sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+        if (sfield == NULL) {                                               \
+            EXPORT_PC();                                                    \
+            sfield = dvmResolveStaticField(curMethod->clazz, ref);          \
+            if (sfield == NULL)                                             \
+                GOTO_exceptionThrown();                                     \
+        }                                                                   \
+        dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst));    \
+        ILOGV("+ SPUT '%s'=0x%08llx",                                       \
+            sfield->field.name, (u8)GET_REGISTER##_regsize(vdst));          \
+        UPDATE_FIELD_PUT(&sfield->field);                                   \
+    }                                                                       \
+    FINISH(2);
+
+
+/* File: cstubs/enddefs.c */
+
+/* undefine "magic" name remapping */
+#undef retval
+#undef pc
+#undef fp
+#undef curMethod
+#undef methodClassDex
+#undef self
+#undef debugTrackedRefStart
+
+/* File: armv5te/debug.c */
+#include <inttypes.h>
+
+/*
+ * Dump the fixed-purpose ARM registers, along with some other info.
+ *
+ * This function MUST be compiled in ARM mode -- THUMB will yield bogus
+ * results.
+ *
+ * This will NOT preserve r0-r3/ip.
+ */
+void dvmMterpDumpArmRegs(uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3)
+{
+    register uint32_t rPC       asm("r4");
+    register uint32_t rFP       asm("r5");
+    register uint32_t rGLUE     asm("r6");
+    register uint32_t rINST     asm("r7");
+    register uint32_t rIBASE    asm("r8");
+    register uint32_t r9        asm("r9");
+    register uint32_t r10       asm("r10");
+
+    extern char dvmAsmInstructionStart[];
+
+    printf("REGS: r0=%08x r1=%08x r2=%08x r3=%08x\n", r0, r1, r2, r3);
+    printf("    : rPC=%08x rFP=%08x rGLUE=%08x rINST=%08x\n",
+        rPC, rFP, rGLUE, rINST);
+    printf("    : rIBASE=%08x r9=%08x r10=%08x\n", rIBASE, r9, r10);
+
+    MterpGlue* glue = (MterpGlue*) rGLUE;
+    const Method* method = glue->method;
+    printf("    + self is %p\n", dvmThreadSelf());
+    //printf("    + currently in %s.%s %s\n",
+    //    method->clazz->descriptor, method->name, method->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-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index 82aba26..7bd8ad3 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -1484,6 +1484,11 @@
 #if defined(WITH_SELF_VERIFICATION)
          (interpState->jitState != kJitSelfVerification) &&
 #endif
+         /*
+          * Don't bail out of the dbg interpreter if the entry reason is to
+          * deal with a thrown exception.
+          */
+         (interpState->entryPoint != kInterpEntryThrow) &&
          !gDvm.debuggerActive &&
 #if defined(WITH_PROFILER)
          (gDvm.activeProfilers == 0) &&
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index 5dd771e..f8b3a75 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -1223,6 +1223,11 @@
 #if defined(WITH_SELF_VERIFICATION)
          (interpState->jitState != kJitSelfVerification) &&
 #endif
+         /*
+          * Don't bail out of the dbg interpreter if the entry reason is to
+          * deal with a thrown exception.
+          */
+         (interpState->entryPoint != kInterpEntryThrow) &&
          !gDvm.debuggerActive &&
 #if defined(WITH_PROFILER)
          (gDvm.activeProfilers == 0) &&
diff --git a/vm/mterp/portable/entry.c b/vm/mterp/portable/entry.c
index 8ea4bdc..6789450 100644
--- a/vm/mterp/portable/entry.c
+++ b/vm/mterp/portable/entry.c
@@ -48,6 +48,11 @@
 #if defined(WITH_SELF_VERIFICATION)
          (interpState->jitState != kJitSelfVerification) &&
 #endif
+         /*
+          * Don't bail out of the dbg interpreter if the entry reason is to
+          * deal with a thrown exception.
+          */
+         (interpState->entryPoint != kInterpEntryThrow) &&
          !gDvm.debuggerActive &&
 #if defined(WITH_PROFILER)
          (gDvm.activeProfilers == 0) &&
diff --git a/vm/mterp/rebuild.sh b/vm/mterp/rebuild.sh
index 44d8abe..841546f 100755
--- a/vm/mterp/rebuild.sh
+++ b/vm/mterp/rebuild.sh
@@ -20,7 +20,7 @@
 #
 set -e
 
-for arch in portstd portdbg allstubs armv4t armv5te armv5te-vfp armv7-a x86 x86-atom; do TARGET_ARCH_EXT=$arch make -f Makefile-mterp; done
+for arch in portstd portdbg allstubs armv4t 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
diff --git a/vm/native/dalvik_system_VMDebug.c b/vm/native/dalvik_system_VMDebug.c
index f2b364b..612c9b5 100644
--- a/vm/native/dalvik_system_VMDebug.c
+++ b/vm/native/dalvik_system_VMDebug.c
@@ -873,6 +873,23 @@
     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();
+}
+
 const DalvikNativeMethod dvm_dalvik_system_VMDebug[] = {
     { "getVmFeatureList",           "()[Ljava/lang/String;",
         Dalvik_dalvik_system_VMDebug_getVmFeatureList },
@@ -928,6 +945,7 @@
         Dalvik_dalvik_system_VMDebug_dumpReferenceTables },
     { "crash",                      "()V",
         Dalvik_dalvik_system_VMDebug_crash },
+    { "infopoint",                 "(I)V",
+        Dalvik_dalvik_system_VMDebug_infopoint },
     { NULL, NULL, NULL },
 };
-
diff --git a/vm/oo/Class.c b/vm/oo/Class.c
index f3cfde2..bbb8a35 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -1674,7 +1674,9 @@
      * Note that we assume that java.lang.Class does not override
      * finalize().
      */
-    newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
+    newClass = (ClassObject*) dvmMalloc(sizeof(*newClass) +
+                 sizeof(StaticField) * pHeader->staticFieldsSize,
+                                        ALLOC_DEFAULT);
     if (newClass == NULL)
         return NULL;
 
@@ -1729,11 +1731,12 @@
     /* load field definitions */
 
     /*
-     * TODO: consider over-allocating the class object and appending the
-     * static field info onto the end.  It's fixed-size and known at alloc
-     * time.  This would save a couple of native heap allocations, but it
-     * would also make heap compaction more difficult because we pass Field
-     * pointers around internally.
+     * Over-allocate the class object and append static field info
+     * onto the end.  It's fixed-size and known at alloc time.  This
+     * seems to increase zygote sharing.  Heap compaction will have to
+     * be careful if it ever tries to move ClassObject instances,
+     * because we pass Field pointers around internally. But at least
+     * now these Field pointers are in the object heap.
      */
 
     if (pHeader->staticFieldsSize != 0) {
@@ -1743,8 +1746,6 @@
         DexField field;
 
         newClass->sfieldCount = count;
-        newClass->sfields =
-            (StaticField*) calloc(count, sizeof(StaticField));
         for (i = 0; i < count; i++) {
             dexReadClassDataField(&pEncodedData, &field, &lastIndex);
             loadSFieldFromDex(newClass, &field, &newClass->sfields[i]);
@@ -2002,7 +2003,8 @@
     NULL_AND_LINEAR_FREE(clazz->ifviPool);
 
     clazz->sfieldCount = -1;
-    NULL_AND_FREE(clazz->sfields);
+    /* The sfields are attached to the ClassObject, and will be freed
+     * with it. */
 
     clazz->ifieldCount = -1;
     NULL_AND_LINEAR_FREE(clazz->ifields);
diff --git a/vm/oo/Object.c b/vm/oo/Object.c
index eff0983..0d2da1f 100644
--- a/vm/oo/Object.c
+++ b/vm/oo/Object.c
@@ -85,7 +85,7 @@
 StaticField* dvmFindStaticField(const ClassObject* clazz,
     const char* fieldName, const char* signature)
 {
-    StaticField* pField;
+    const StaticField* pField;
     int i;
 
     assert(clazz != NULL);
@@ -95,12 +95,12 @@
      * fields, the VM allows you to have two fields with the same name so
      * long as they have different types.
      */
-    pField = clazz->sfields;
+    pField = &clazz->sfields[0];
     for (i = 0; i < clazz->sfieldCount; i++, pField++) {
         if (strcmp(fieldName, pField->field.name) == 0 &&
             strcmp(signature, pField->field.signature) == 0)
         {
-            return pField;
+            return (StaticField*) pField;
         }
     }
 
@@ -739,4 +739,3 @@
         clazz = clazz->super;
     }
 }
-
diff --git a/vm/oo/Object.h b/vm/oo/Object.h
index df167d5..be2c9f2 100644
--- a/vm/oo/Object.h
+++ b/vm/oo/Object.h
@@ -320,6 +320,45 @@
 };
 
 /*
+ * Generic field header.  We pass this around when we want a generic Field
+ * pointer (e.g. for reflection stuff).  Testing the accessFlags for
+ * ACC_STATIC allows a proper up-cast.
+ */
+struct Field {
+    ClassObject*    clazz;          /* class in which the field is declared */
+    const char*     name;
+    const char*     signature;      /* e.g. "I", "[C", "Landroid/os/Debug;" */
+    u4              accessFlags;
+#ifdef PROFILE_FIELD_ACCESS
+    u4              gets;
+    u4              puts;
+#endif
+};
+
+/*
+ * Static field.
+ */
+struct StaticField {
+    Field           field;          /* MUST be first item */
+    JValue          value;          /* initially set from DEX for primitives */
+};
+
+/*
+ * Instance field.
+ */
+struct InstField {
+    Field           field;          /* MUST be first item */
+
+    /*
+     * This field indicates the byte offset from the beginning of the
+     * (Object *) to the actual instance data; e.g., byteOffset==0 is
+     * the same as the object pointer (bug!), and byteOffset==4 is 4
+     * bytes farther.
+     */
+    int             byteOffset;
+};
+
+/*
  * This defines the amount of space we leave for field slots in the
  * java.lang.Class definition.  If we alter the class to have more than
  * this many fields, the VM will abort at startup.
@@ -443,10 +482,6 @@
     int             ifviPoolCount;
     int*            ifviPool;
 
-    /* static fields */
-    int             sfieldCount;
-    StaticField*    sfields;
-
     /* instance fields
      *
      * These describe the layout of the contents of a DataObject-compatible
@@ -467,6 +502,10 @@
 
     /* source file name, if known */
     const char*     sourceFile;
+
+    /* static fields */
+    int             sfieldCount;
+    StaticField     sfields[]; /* MUST be last item */
 };
 
 /*
@@ -555,45 +594,6 @@
 #endif
 };
 
-/*
- * Generic field header.  We pass this around when we want a generic Field
- * pointer (e.g. for reflection stuff).  Testing the accessFlags for
- * ACC_STATIC allows a proper up-cast.
- */
-struct Field {
-    ClassObject*    clazz;          /* class in which the field is declared */
-    const char*     name;
-    const char*     signature;      /* e.g. "I", "[C", "Landroid/os/Debug;" */
-    u4              accessFlags;
-#ifdef PROFILE_FIELD_ACCESS
-    u4              gets;
-    u4              puts;
-#endif
-};
-
-/*
- * Static field.
- */
-struct StaticField {
-    Field           field;          /* MUST be first item */
-    JValue          value;          /* initially set from DEX for primitives */
-};
-
-/*
- * Instance field.
- */
-struct InstField {
-    Field           field;          /* MUST be first item */
-
-    /*
-     * This field indicates the byte offset from the beginning of the
-     * (Object *) to the actual instance data; e.g., byteOffset==0 is
-     * the same as the object pointer (bug!), and byteOffset==4 is 4
-     * bytes farther.
-     */
-    int             byteOffset;
-};
-
 
 /*
  * Find a method within a class.  The superclass is not searched.
diff --git a/vm/reflect/Proxy.c b/vm/reflect/Proxy.c
index 31df708..4270894 100644
--- a/vm/reflect/Proxy.c
+++ b/vm/reflect/Proxy.c
@@ -47,6 +47,7 @@
 
 /* private static fields in the Proxy class */
 #define kThrowsField    0
+#define kProxySFieldCount 1
 
 
 /*
@@ -177,7 +178,9 @@
     /*
      * Allocate storage for the class object and set some basic fields.
      */
-    newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
+    newClass = (ClassObject*) dvmMalloc(sizeof(*newClass) +
+                                        kProxySFieldCount * sizeof(StaticField),
+                                        ALLOC_DEFAULT);
     if (newClass == NULL)
         goto bail;
     DVM_OBJECT_INIT(&newClass->obj, gDvm.unlinkedJavaLangClass);
@@ -228,8 +231,8 @@
      * Static field list.  We have one private field, for our list of
      * exceptions declared for each method.
      */
-    newClass->sfieldCount = 1;
-    newClass->sfields = (StaticField*) calloc(1, sizeof(StaticField));
+    assert(kProxySFieldCount == 1);
+    newClass->sfieldCount = kProxySFieldCount;
     StaticField* sfield = &newClass->sfields[kThrowsField];
     sfield->field.clazz = newClass;
     sfield->field.name = "throws";
@@ -1094,4 +1097,3 @@
     /* no match in declared throws */
     return true;
 }
-
diff --git a/vm/reflect/Reflect.c b/vm/reflect/Reflect.c
index 2e3c549..38b1ed0 100644
--- a/vm/reflect/Reflect.c
+++ b/vm/reflect/Reflect.c
@@ -306,7 +306,7 @@
     int slot;
 
     if (dvmIsStaticField(field)) {
-        slot = (StaticField*)field - clazz->sfields;
+        slot = (StaticField*)field - &clazz->sfields[0];
         assert(slot >= 0 && slot < clazz->sfieldCount);
         slot = -(slot+1);
     } else {
@@ -1255,4 +1255,3 @@
         return dvmCreateReflectMethodObject(method);
     }
 }
-