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 "chain" will still
- * have this method called, and (b) the class definition or
- * redefinition that was the catalyst for the transformation
- * opportunities will still be attempted.
- */
- public byte[] transform(ClassLoader loader, String className,
- Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
- byte[] classfileBuffer) throws IllegalClassFormatException;
-}
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/IllegalClassFormatException.java b/libcore-disabled/instrument/src/main/java/java/lang/instrument/IllegalClassFormatException.java
deleted file mode 100644
index 9696bfe..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/IllegalClassFormatException.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.instrument;
-
-/**
- * This exception may be thrown from implementations of the method
- * {@link java.lang.instrument.ClassFileTransformer#transform} when the class
- * file bytes supplied to it are found to be corrupted or otherwise in a format
- * which does not adhere to the expected Java class file format.
- *
- */
-public class IllegalClassFormatException extends Exception {
-
- private static final long serialVersionUID = -3841736710924794009L;
-
- /**
- * Constructs a new instance of <code>IllegalClassFormatException</code>
- * with no explanatory message.
- */
- public IllegalClassFormatException() {
- super();
- }
-
- /**
- * Constructs a new instance of <code>IllegalClassFormatException</code>
- * with the supplied message, <code>s</code>, for explanation.
- *
- * @param s
- * a string containing information on why the exception is being
- * created.
- */
- public IllegalClassFormatException(String s) {
- super(s);
- }
-}
\ No newline at end of file
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/Instrumentation.java b/libcore-disabled/instrument/src/main/java/java/lang/instrument/Instrumentation.java
deleted file mode 100644
index 6dd053f..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/Instrumentation.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.instrument;
-
-/**
- * Instances of this interface may be used by Java instrumentation agent code
- * for support in carrying out the runtime instrumentation of classes. Using
- * such an approach, classes may be enhanced with services such as profiling,
- * logging or tracing which were not included in the source of the original
- * class.
- * <p>
- * A concrete instance of this interface is made available as an input argument
- * to all Java instrumentation agents'
- * <code>premain(String agentArgs, Instrumentation inst)</code> method.
- * </p>
- *
- */
-public interface Instrumentation {
-
- /**
- * Registers the supplied <code>transformer</code> argument with the VM.
- * Any classes that are to be defined or re-defined (if supported) in the VM
- * will then be offered to the transformer for it to carry out any byte code
- * modifications. The exception to this scheme is if the class to be defined /
- * re-defined is a dependency of the transformer.
- * <p>
- * This operation can be carried out multiple times on a concrete
- * <code>Instrumentation</code>. The order of registration is important
- * as it defines the order in which the transformers' transformation
- * operation gets called.
- * <p>
- * <p>
- * It is possible for any given instance of
- * <code>ClassFileTransformer</code> to be registered more than once with
- * this operation.
- *
- * @param transformer
- * a class file transformer
- * @throws NullPointerException
- * if <code>transformer</code> is <code>null</code>.
- */
- public void addTransformer(ClassFileTransformer transformer);
-
- /**
- * Returns an array of all of the classes that have been loaded into the VM.
- *
- * @return an array of <code>Class</code> objects with each element
- * identifying a class that has been loaded into the VM.
- */
- public Class[] getAllLoadedClasses();
-
- /**
- * Returns an array of all of the classes for which <code>loader</code> is
- * the <i>initiating</i> class loader.
- *
- * @param loader
- * a class loader. In order to obtain the array of classes
- * initiated by the bootstrap class loader this argument should
- * be <code>null</code>.
- * @return an array of <code>Class</code> objects with each element
- * identifying a class that has been initiated by the specified
- * class loader.
- */
- public Class[] getInitiatedClasses(ClassLoader loader);
-
- /**
- * Returns the number of bytes in memory required by this VM for the
- * supplied object <code>objectToSize</code>. The returned value should
- * be taken as an estimation only which is susceptible to change between
- * separate launches of the VM.
- *
- * @param objectToSize
- * any object
- * @return an approximation of the number of bytes in memory taken up by
- * <code>objectToSize</code>.
- * @throws NullPointerException
- * if the given object is null.
- */
- public long getObjectSize(Object objectToSize);
-
- /**
- * Returns a boolean indication of whether or not this VM supports the
- * on-the-fly redefining of classes that have been already loaded.
- *
- * @return <code>true</code> if class redefining is supported, otherwise
- * <code>false</code>.
- */
- public boolean isRedefineClassesSupported();
-
- /**
- * Receives an array of {@link ClassDefinition} instances and attempts to
- * carry out on-the-fly redefining on each of the associated classes.
- * Redefining in this manner may be used to update the following parts of an
- * already loaded class:
- * <ul>
- * <li>attributes
- * <li>constant pool
- * <li>method implementations
- * </ul>
- * If any invocations of a redefined method are already active in the VM
- * when this call is made then they will run to completion and be unaffected
- * by the outcome of this method. Provided the method redefinition is
- * successful, all subsequent calls on the method will run the new version.
- * <br>
- * Redefining a class may <em>not</em> be used to make changes to any
- * other aspects of a previously loaded class such as its inheritance
- * hierarchy, the names or signatures of any of its methods, the names of
- * any fields, the values of any static variables etc.
- * <p>
- * If a class associated with a <code>ClassDefinition</code> is
- * successfully redefined then there will be no resulting re-run of any of
- * its initialization code. Similarly, any instances of the class that were
- * created before the redefining will not be changed in any way. That is,
- * they will remain in the VM as instances of the previous version of the
- * class.
- * </p>
- * <p>
- * Note that before the requested redefinitions are attempted, each
- * {@link ClassFileTransformer} registered with the VM will be given the
- * opportunity to carry out their own custom transformations of the new
- * version of the class.
- * </p>
- *
- * @param definitions
- * an array of <code>ClassDefinition</code> objects wrapping
- * the details of the classes to be redefined. A zero-length
- * array value will not cause an error but, instead, will
- * silently do nothing.
- * @throws ClassNotFoundException
- * if any of the classes specified in the contents of
- * <code>definitions</code> cannot be located.
- * @throws UnmodifiableClassException
- * if any of the classes specified in the contents of
- * <code>definitions</code> cannot be modified.
- * @throws UnsupportedOperationException
- * if this method is not supported in by the VM. May be checked
- * in advance by calling {@link #isRedefineClassesSupported()}.
- * @throws ClassFormatError
- * if any of the <code>definitions</code> elements has been
- * created with a <code>byte</code> array containing a badly
- * formed class file.
- * @throws NoClassDefFoundError
- * if there is disagreement between the name of a class to be
- * redefined and the name of the class from the corresponding
- * class file format byte array.
- * @throws UnsupportedClassVersionError
- * if the version of any of the classes to be redefined is not
- * supported by the VM.
- * @throws ClassCircularityError
- * if a circular dependency is detected among the classes to be
- * redefined.
- * @throws LinkageError
- * if a linkage error situation is detected such that there is
- * an incompatability between dependent classes.
- * @throws NullPointerException
- * if <code>definitions</code> or any of its elements are
- * found to be <code>null</code>.
- * @see #isRedefineClassesSupported()
- */
- public void redefineClasses(ClassDefinition[] definitions)
- throws ClassNotFoundException, UnmodifiableClassException;
-
- /**
- * Removes <i>the most recently added instance of</i> the
- * <code>ClassFileTransformer</code> object from the VM's list of
- * registered transformers. After this call completes, the specified
- * <code>ClassFileTransformer</code> object will no longer have its
- * <code>transform()<code> method automatically invoked when class definitions or
- * redefinitions are attempted.
- *
- * @param transformer
- * a previously registered <code>ClassFileTransformer</code>.
- * @return <code>true</code> if <code>transformer</code> was located in
- * the list of registered transformers and successfully removed.
- * Otherwise, <code>false</code>.
- * @throws NullPointerException
- * if <code>transformer</code> is <code>null</code>.
- */
- public boolean removeTransformer(ClassFileTransformer transformer);
-}
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/UnmodifiableClassException.java b/libcore-disabled/instrument/src/main/java/java/lang/instrument/UnmodifiableClassException.java
deleted file mode 100644
index e8c8d57..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/UnmodifiableClassException.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package java.lang.instrument;
-
-/**
- * This exception may be thrown from implementations of the method
- * {@link java.lang.instrument.Instrumentation#redefineClasses} when one of the
- * desired class redefinition operations cannot be carried out. Such a situation
- * may arise if a redefinition attempts to alter the members of a class or its
- * inheritance hierarchy.
- *
- */
-public class UnmodifiableClassException extends Exception {
-
- private static final long serialVersionUID = 1716652643585309178L;
-
- /**
- * Constructs a new instance of <code>UnmodifiableClassException</code>
- * with no explanatory message.
- */
- public UnmodifiableClassException() {
- super();
- }
-
- /**
- * Constructs a new instance of <code>UnmodifiableClassException</code>
- * with the supplied message, <code>s</code>, for explanation.
- *
- * @param s
- * a string containing information on why the exception is being
- * created.
- */
- public UnmodifiableClassException(String s) {
- super(s);
- }
-}
diff --git a/libcore-disabled/instrument/src/main/java/java/lang/instrument/package.html b/libcore-disabled/instrument/src/main/java/java/lang/instrument/package.html
deleted file mode 100644
index 50224d7..0000000
--- a/libcore-disabled/instrument/src/main/java/java/lang/instrument/package.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
- <body>
- <p>
- Provides classes and interfaces needed for instrumenting applications.
- <p>
- </body>
-</html>
\ No newline at end of file
diff --git a/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/Messages.java b/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/Messages.java
deleted file mode 100644
index cdde768..0000000
--- a/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/Messages.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
- * All changes made to this file manually will be overwritten
- * if this tool runs again. Better make changes in the template file.
- */
-
-package org.apache.harmony.instrument.internal.nls;
-
-// BEGIN android-added
-import org.apache.harmony.luni.util.MsgHelp;
-// END android-added
-
-/**
- * This class retrieves strings from a resource bundle and returns them,
- * formatting them with MessageFormat when required.
- * <p>
- * It is used by the system classes to provide national language support, by
- * looking up messages in the <code>
- * org.apache.harmony.instrument.internal.nls.messages
- * </code>
- * resource bundle. Note that if this file is not available, or an invalid key
- * is looked up, or resource bundle support is not available, the key itself
- * will be returned as the associated message. This means that the <em>KEY</em>
- * should a reasonable human-readable (english) string.
- *
- */
-public class Messages {
-
- // BEGIN android-changed
- private static final String sResource =
- "org.apache.harmony.instrument.internal.nls.messages";
- // END android-changed
-
- /**
- * Retrieves a message which has no arguments.
- *
- * @param msg
- * String the key to look up.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg) {
- // BEGIN android-changed
- return MsgHelp.getString(sResource, msg);
- // END android-changed
- }
-
- /**
- * Retrieves a message which takes 1 argument.
- *
- * @param msg
- * String the key to look up.
- * @param arg
- * Object the object to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, Object arg) {
- return getString(msg, new Object[] { arg });
- }
-
- /**
- * Retrieves a message which takes 1 integer argument.
- *
- * @param msg
- * String the key to look up.
- * @param arg
- * int the integer to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, int arg) {
- return getString(msg, new Object[] { Integer.toString(arg) });
- }
-
- /**
- * Retrieves a message which takes 1 character argument.
- *
- * @param msg
- * String the key to look up.
- * @param arg
- * char the character to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, char arg) {
- return getString(msg, new Object[] { String.valueOf(arg) });
- }
-
- /**
- * Retrieves a message which takes 2 arguments.
- *
- * @param msg
- * String the key to look up.
- * @param arg1
- * Object an object to insert in the formatted output.
- * @param arg2
- * Object another object to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, Object arg1, Object arg2) {
- return getString(msg, new Object[] { arg1, arg2 });
- }
-
- /**
- * Retrieves a message which takes several arguments.
- *
- * @param msg
- * String the key to look up.
- * @param args
- * Object[] the objects to insert in the formatted output.
- * @return String the message for that key in the system message bundle.
- */
- static public String getString(String msg, Object[] args) {
- // BEGIN android-changed
- return MsgHelp.getString(sResource, msg, args);
- // END android-changed
- }
-}
diff --git a/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/messages.properties b/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/messages.properties
deleted file mode 100644
index 6c59186..0000000
--- a/libcore-disabled/instrument/src/main/java/org/apache/harmony/instrument/internal/nls/messages.properties
+++ /dev/null
@@ -1,21 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# messages for EN locale
-instrument.1=Received null class argument.
-instrument.2=Received null class file argument.
-instrument.3=Redefinition operation is not supported!
-instrument.4=Fatal error: failed to execute premain class of java agent.
diff --git a/libcore-disabled/sound/MODULE_LICENSE_APACHE2 b/libcore-disabled/sound/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/libcore-disabled/sound/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidMidiFileReader.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidMidiFileReader.java
deleted file mode 100644
index fb6b0e5..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidMidiFileReader.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.midi;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.MidiFileFormat;
-import javax.sound.midi.Sequence;
-import javax.sound.midi.spi.MidiFileReader;
-
-/**
- * Implements a MidiFileReader for Android. We need to cache data coming from an
- * arbitrary InputStream, since the Android MediaPlayer expects us to pass in a
- * file or a URL.
- */
-public class AndroidMidiFileReader extends MidiFileReader {
-
- @Override
- public MidiFileFormat getMidiFileFormat(File file) throws InvalidMidiDataException, IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public MidiFileFormat getMidiFileFormat(InputStream stream) throws InvalidMidiDataException,
- IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public MidiFileFormat getMidiFileFormat(URL url) throws InvalidMidiDataException, IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Sequence getSequence(File file) throws InvalidMidiDataException, IOException {
- return new AndroidSequence(file.toURL());
- }
-
- @Override
- public Sequence getSequence(InputStream stream) throws InvalidMidiDataException, IOException {
- File file = File.createTempFile("javax.sound.midi-", null);
- file.deleteOnExit();
-
- BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
- byte[] buffer = new byte[1024];
-
- int count = stream.read(buffer);
- while (count >= 0) {
- out.write(buffer, 0, count);
- count = stream.read(buffer);
- }
-
- out.flush();
- out.close();
-
- return getSequence(file);
- }
-
- @Override
- public Sequence getSequence(URL url) throws InvalidMidiDataException, IOException {
- return new AndroidSequence(url);
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequence.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequence.java
deleted file mode 100644
index 861f970..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequence.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.midi;
-
-import java.net.URL;
-
-import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.Sequence;
-
-/**
- * Implements a MIDI Sequence for Android. Its set of tracks etc. will always
- * be empty (at least we don't care about the contents). Instead, we store the
- * URL to the original MIDI data in it, so we can feed it into the Android
- * MediaPlayer.
- */
-public class AndroidSequence extends Sequence {
-
- /**
- * Holds the URL to the MIDI data.
- */
- private URL url;
-
- /**
- * Creates a new AndroidSequence.
- *
- * @param url The URL that points to the MIDI data.
- *
- * @throws InvalidMidiDataException If the MIDI data is invalid (which we
- * actually don't check at all).
- */
- public AndroidSequence(URL url) throws InvalidMidiDataException {
- super(0.0f, 1);
-
- this.url = url;
- }
-
- /**
- * Returns the URL pointing to the MIDI data.
- *
- * @return The URL.
- */
- URL getURL() {
- return url;
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequencer.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequencer.java
deleted file mode 100644
index 6b3ea20..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/midi/AndroidSequencer.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.midi;
-
-import android.media.AudioManager;
-import android.media.MediaPlayer;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.sound.midi.ControllerEventListener;
-import javax.sound.midi.InvalidMidiDataException;
-import javax.sound.midi.MetaEventListener;
-import javax.sound.midi.MidiDevice;
-import javax.sound.midi.MidiUnavailableException;
-import javax.sound.midi.Receiver;
-import javax.sound.midi.Sequence;
-import javax.sound.midi.Sequencer;
-import javax.sound.midi.Track;
-import javax.sound.midi.Transmitter;
-
-/**
- * Implements a MIDI Sequencer for Android. Since Android's MediaPlayer is
- * somewhat limited, we only support MIDI playback, but not recording or the
- * querying of MIDI information. Many of the methods hence throw
- * {@link java.lang.UnsupportedOperationException} or return dummy results.
- */
-public class AndroidSequencer implements Sequencer {
-
- /**
- * Defines the DeviceInfo for our AndroidSequencer.
- */
- private class Info extends MidiDevice.Info {
- public Info() {
- super("Android Sequencer", "Android Sequencer", "The Android Project", "1.0");
- }
- }
-
- /**
- * Holds the Android MediaPlayer we use.
- */
- private MediaPlayer player;
-
- /**
- * Holds the Android Sequence we want to play.
- */
- private AndroidSequence sequence;
-
- public int[] addControllerEventListener(ControllerEventListener listener, int[] controllers) {
- throw new UnsupportedOperationException();
- }
-
- public boolean addMetaEventListener(MetaEventListener listener) {
- throw new UnsupportedOperationException();
- }
-
- public int getLoopCount() {
- throw new UnsupportedOperationException();
- }
-
- public long getLoopEndPoint() {
- throw new UnsupportedOperationException();
- }
-
- public long getLoopStartPoint() {
- throw new UnsupportedOperationException();
- }
-
- public SyncMode getMasterSyncMode() {
- throw new UnsupportedOperationException();
- }
-
- public SyncMode[] getMasterSyncModes() {
- throw new UnsupportedOperationException();
- }
-
- public long getMicrosecondLength() {
- throw new UnsupportedOperationException();
- }
-
- public long getMicrosecondPosition() {
- throw new UnsupportedOperationException();
- }
-
- public Sequence getSequence() {
- return sequence;
- }
-
- public SyncMode getSlaveSyncMode() {
- throw new UnsupportedOperationException();
- }
-
- public SyncMode[] getSlaveSyncModes() {
- throw new UnsupportedOperationException();
- }
-
- public float getTempoFactor() {
- throw new UnsupportedOperationException();
- }
-
- public float getTempoInBPM() {
- throw new UnsupportedOperationException();
- }
-
- public float getTempoInMPQ() {
- throw new UnsupportedOperationException();
- }
-
- public long getTickLength() {
- throw new UnsupportedOperationException();
- }
-
- public long getTickPosition() {
- throw new UnsupportedOperationException();
- }
-
- public boolean getTrackMute(int track) {
- throw new UnsupportedOperationException();
- }
-
- public boolean getTrackSolo(int track) {
- throw new UnsupportedOperationException();
- }
-
- public boolean isRecording() {
- return false;
- }
-
- public boolean isRunning() {
- return player != null && player.isPlaying();
- }
-
- public void recordDisable(Track track) {
- throw new UnsupportedOperationException();
- }
-
- public void recordEnable(Track track, int channel) {
- throw new UnsupportedOperationException();
- }
-
- public int[] removeControllerEventListener(ControllerEventListener listener, int[] controllers) {
- throw new UnsupportedOperationException();
- }
-
- public void removeMetaEventListener(MetaEventListener listener) {
- throw new UnsupportedOperationException();
- }
-
- public void setLoopCount(int count) {
- throw new UnsupportedOperationException();
- }
-
- public void setLoopEndPoint(long tick) {
- throw new UnsupportedOperationException();
- }
-
- public void setLoopStartPoint(long tick) {
- throw new UnsupportedOperationException();
- }
-
- public void setMasterSyncMode(SyncMode sync) {
- throw new UnsupportedOperationException();
- }
-
- public void setMicrosecondPosition(long microseconds) {
- throw new UnsupportedOperationException();
- }
-
- public void setSequence(InputStream stream) throws IOException, InvalidMidiDataException {
- setSequence(new AndroidMidiFileReader().getSequence(stream));
- }
-
- public void setSequence(Sequence sequence) throws InvalidMidiDataException {
- if (!(sequence instanceof AndroidSequence)) {
- throw new InvalidMidiDataException("Sequence must be an AndroidSequence");
- }
-
- if (isRunning()) {
- stop();
- }
-
- this.sequence = (AndroidSequence)sequence;
- }
-
- public void setSlaveSyncMode(SyncMode sync) {
- throw new UnsupportedOperationException();
- }
-
- public void setTempoFactor(float factor) {
- throw new UnsupportedOperationException();
- }
-
- public void setTempoInBPM(float bpm) {
- throw new UnsupportedOperationException();
- }
-
- public void setTempoInMPQ(float mpq) {
- throw new UnsupportedOperationException();
- }
-
- public void setTickPosition(long tick) {
- throw new UnsupportedOperationException();
- }
-
- public void setTrackMute(int track, boolean mute) {
- throw new UnsupportedOperationException();
- }
-
- public void setTrackSolo(int track, boolean solo) {
- throw new UnsupportedOperationException();
- }
-
- public void start() {
- if (!isOpen()) {
- throw new IllegalStateException("Sequencer must be open");
- }
-
- if (sequence == null) {
- throw new IllegalStateException("Need a Sequence to play");
- }
-
- if (!isRunning()) {
- /*
- * This is ugly, but there is no way around it: The javax.sound API
- * doesn't expect to throw an exception at this point for illegal
- * MIDI sequences. Since we don't really construct the MIDI sequence
- * from the original binary data, but only refer to its URL, the
- * MediaPlayer can actually bail out at this point. We wrap the
- * exception into a RuntimeException, to at least keep the API
- * contract.
- */
- try {
- String s = this.sequence.getURL().toExternalForm();
-
- /*
- * TODO Workaround for 1107794: MediaPlayer doesn't handle
- * "file:" URLs. Get rid of this.
- */
- if (s.startsWith("file:")) {
- s = s.substring(5);
- }
-
- player.setDataSource(s);
- player.setAudioStreamType(AudioManager.STREAM_MUSIC);
- player.prepare();
- } catch (IOException ex) {
- throw new RuntimeException(ex.toString());
- }
-
- player.start();
- }
- }
-
- public void startRecording() {
- throw new UnsupportedOperationException();
- }
-
- public void stop() {
- if (!isOpen()) {
- throw new IllegalStateException("Sequencer must be open");
- }
-
- if (isRunning()) {
- player.stop();
- }
- }
-
- public void stopRecording() {
- throw new UnsupportedOperationException();
- }
-
- public void close() {
- if (isOpen()) {
- stop();
- player = null;
- }
- }
-
- public Info getDeviceInfo() {
- return new Info();
- }
-
- public int getMaxReceivers() {
- return 0;
- }
-
- public int getMaxTransmitters() {
- return 0;
- }
-
- public Receiver getReceiver() throws MidiUnavailableException {
- throw new MidiUnavailableException("No receiver available");
- }
-
- public List<Receiver> getReceivers() {
- return new ArrayList<Receiver>();
- }
-
- public Transmitter getTransmitter() throws MidiUnavailableException {
- throw new MidiUnavailableException("No receiver available");
- }
-
- public List<Transmitter> getTransmitters() {
- return new ArrayList<Transmitter>();
- }
-
- public boolean isOpen() {
- return player != null;
- }
-
- public void open() throws MidiUnavailableException {
- try {
- player = new MediaPlayer();
- } catch (Exception ex) {
- throw new MidiUnavailableException(ex.toString());
- }
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioFileReader.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioFileReader.java
deleted file mode 100644
index f9b1d47..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioFileReader.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.sampled;
-
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import javax.sound.sampled.AudioFileFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.UnsupportedAudioFileException;
-import javax.sound.sampled.spi.AudioFileReader;
-
-/**
- * Implements an AudioFileReader for Android. We need to cache data coming from
- * an arbitrary InputStream, since the Android MediaPlayer expects us to pass in
- * a file or URL.
- */
-public class AndroidAudioFileReader extends AudioFileReader {
-
- @Override
- public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException,
- IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public AudioFileFormat getAudioFileFormat(InputStream stream)
- throws UnsupportedAudioFileException, IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public AudioFileFormat getAudioFileFormat(URL url) throws UnsupportedAudioFileException,
- IOException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException,
- IOException {
- return new AndroidAudioInputStream(file.toURL());
- }
-
- @Override
- public AudioInputStream getAudioInputStream(InputStream stream)
- throws UnsupportedAudioFileException, IOException {
- File file = File.createTempFile("javax.sound.sampled-", null);
- file.deleteOnExit();
-
- BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
- byte[] buffer = new byte[1024];
-
- int count = stream.read(buffer);
- while (count >= 0) {
- out.write(buffer, 0, count);
- count = stream.read(buffer);
- }
-
- out.flush();
- out.close();
-
- return getAudioInputStream(file);
- }
-
- @Override
- public AudioInputStream getAudioInputStream(URL url) throws UnsupportedAudioFileException,
- IOException {
- return new AndroidAudioInputStream(url);
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioInputStream.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioInputStream.java
deleted file mode 100644
index ba97021..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidAudioInputStream.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.sampled;
-
-import java.net.URL;
-
-import javax.sound.sampled.AudioFormat;
-import javax.sound.sampled.AudioInputStream;
-
-/**
- * Implements an AudioInputStream for Android. Its internal InputStream is
- * unused (at least we don't care about the contents). Instead, we store the
- * URL to the original audio data in it, so we can feed it into the Android
- * MediaPlayer.
- */
-public class AndroidAudioInputStream extends AudioInputStream {
-
- /**
- * Holds the URL to the MIDI data.
- */
- private URL url;
-
- /**
- * Creates a new AndroidAudioInputStream.
- *
- * @param url The URL that points to the audio data.
- */
- public AndroidAudioInputStream(URL url) {
- super(null, new AudioFormat(0.0f, 0, 0, false, false), 0);
-
- this.url = url;
- }
-
- /**
- * Returns the URL pointing to the audio data.
- *
- * @return The URL.
- */
- URL getURL() {
- return url;
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidClip.java b/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidClip.java
deleted file mode 100644
index d70eec1..0000000
--- a/libcore-disabled/sound/src/main/java/com/android/internal/sound/sampled/AndroidClip.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.sound.sampled;
-
-import android.media.AudioManager;
-import android.media.MediaPlayer;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.sound.sampled.AudioFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.Clip;
-import javax.sound.sampled.Control;
-import javax.sound.sampled.Line;
-import javax.sound.sampled.LineListener;
-import javax.sound.sampled.LineUnavailableException;
-import javax.sound.sampled.Control.Type;
-
-/**
- * Implements an audio Clip for Android. Since Android's MediaPlayer is somewhat
- * limited, we only support sample playback, but not recording or the querying
- * of sample information. Many of the methods hence throw
- * {@link java.lang.UnsupportedOperationException} or return dummy results.
- */
-public class AndroidClip implements Clip {
-
- /**
- * Holds the Android MediaPlayer we use.
- */
- private MediaPlayer player;
-
- /**
- * Holds the AndroidAudioInputStream we want to play.
- */
- private AndroidAudioInputStream stream;
-
- public int getFrameLength() {
- throw new UnsupportedOperationException();
- }
-
- public long getMicrosecondLength() {
- throw new UnsupportedOperationException();
- }
-
- public void loop(int count) {
- throw new UnsupportedOperationException();
- }
-
- public void open(AudioFormat format, byte[] data, int offset, int bufferSize)
- throws LineUnavailableException {
- InputStream stream = new ByteArrayInputStream(data, offset, bufferSize);
-
- open();
-
- try {
- this.stream = (AndroidAudioInputStream)(new AndroidAudioFileReader().getAudioInputStream(stream));
- } catch (Exception ex) {
- throw new LineUnavailableException(ex.toString());
- }
- }
-
- public void open(AudioInputStream stream) throws LineUnavailableException, IOException {
- open();
-
- if (!(stream instanceof AndroidAudioInputStream)) {
- try {
- stream = new AndroidAudioFileReader().getAudioInputStream(stream);
- } catch (Exception ex) {
- throw new LineUnavailableException(ex.toString());
- }
- }
-
- this.stream = (AndroidAudioInputStream)stream;
- }
-
- public void setFramePosition(int frames) {
- throw new UnsupportedOperationException();
- }
-
- public void setLoopPoints(int start, int end) {
- throw new UnsupportedOperationException();
- }
-
- public void setMicrosecondPosition(long microseconds) {
- if (!isOpen()) {
- throw new IllegalStateException("Clip must be open");
- }
-
- player.seekTo((int)(microseconds / 1000));
- }
-
- public int available() {
- throw new UnsupportedOperationException();
- }
-
- public void drain() {
- }
-
- public void flush() {
- }
-
- public int getBufferSize() {
- throw new UnsupportedOperationException();
- }
-
- public AudioFormat getFormat() {
- throw new UnsupportedOperationException();
- }
-
- public int getFramePosition() {
- throw new UnsupportedOperationException();
- }
-
- public float getLevel() {
- throw new UnsupportedOperationException();
- }
-
- public long getLongFramePosition() {
- throw new UnsupportedOperationException();
- }
-
- public long getMicrosecondPosition() {
- if (isOpen()) {
- return player.getCurrentPosition() * 1000;
- } else {
- return 0;
- }
- }
-
- public boolean isActive() {
- return false;
- }
-
- public boolean isRunning() {
- return player != null && player.isPlaying();
- }
-
- public void start() {
- if (!isOpen()) {
- throw new IllegalStateException("Clip must be open");
- }
-
- if (stream == null) {
- throw new IllegalStateException("Need an AudioInputStream to play");
- }
-
- if (!isRunning()) {
- /*
- * This is ugly, but there is no way around it: The javax.sound API
- * doesn't expect to throw an exception at this point for illegal
- * MIDI sequences. Since we don't really construct the MIDI sequence
- * from the original binary data, but only refer to its URL, the
- * MediaPlayer can actually bail out at this point. We wrap the
- * exception into a RuntimeException, to at least keep the API
- * contract.
- */
- try {
- String s = this.stream.getURL().toExternalForm();
-
- /*
- * TODO Workaround for 1107794: MediaPlayer doesn't handle
- * "file:" URLs. Get rid of this.
- */
- if (s.startsWith("file:")) {
- s = s.substring(5);
- }
-
- player.setDataSource(s);
- player.setAudioStreamType(AudioManager.STREAM_MUSIC);
- player.prepare();
- } catch (IOException ex) {
- throw new RuntimeException(ex.toString());
- }
-
- player.start();
- }
- }
-
- public void stop() {
- if (!isOpen()) {
- throw new IllegalStateException("Clip must be open");
- }
-
- if (isRunning()) {
- player.stop();
- }
- }
-
- public void addLineListener(LineListener listener) {
- throw new UnsupportedOperationException();
- }
-
- public void close() {
- if (isOpen()) {
- stop();
- player = null;
- }
- }
-
- public Control getControl(Type control) {
- throw new IllegalArgumentException("No controls available");
- }
-
- public Control[] getControls() {
- return new Control[0];
- }
-
- public javax.sound.sampled.Line.Info getLineInfo() {
- return new Line.Info(this.getClass());
- }
-
- public boolean isControlSupported(Type control) {
- return false;
- }
-
- public boolean isOpen() {
- return player != null;
- }
-
- public void open() throws LineUnavailableException {
- try {
- player = new MediaPlayer();
- } catch (Exception ex) {
- throw new LineUnavailableException(ex.toString());
- }
- }
-
- public void removeLineListener(LineListener listener) {
- throw new UnsupportedOperationException();
- }
-
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/ControllerEventListener.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/ControllerEventListener.java
deleted file mode 100644
index 318139d..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/ControllerEventListener.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.EventListener;
-
-public interface ControllerEventListener extends EventListener {
- void controlChange(ShortMessage event);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/Instrument.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/Instrument.java
deleted file mode 100644
index 397e53e..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/Instrument.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public abstract class Instrument extends SoundbankResource {
- private Patch patch;
-
- protected Instrument(Soundbank soundbank, Patch patch, String name, Class<?> dataClass) {
- super(soundbank, name, dataClass);
- this.patch = patch;
- }
-
- public Patch getPatch() {
- return patch;
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/InvalidMidiDataException.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/InvalidMidiDataException.java
deleted file mode 100644
index bc1cb83..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/InvalidMidiDataException.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public class InvalidMidiDataException extends Exception {
- private static final long serialVersionUID = 2780771756789932067L;
-
- public InvalidMidiDataException() {
- super();
- }
-
- public InvalidMidiDataException(String message) {
- super(message);
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaEventListener.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaEventListener.java
deleted file mode 100644
index 0cf0d38..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaEventListener.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.EventListener;
-
-public interface MetaEventListener extends EventListener {
- void meta(MetaMessage meta);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaMessage.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaMessage.java
deleted file mode 100644
index fe5d9cf..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MetaMessage.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public class MetaMessage extends MidiMessage {
- public static final int META = 255;
-
- private int dsp; //displacement from begin of array that
- //return by method getData() from begin
- //of array that contain data
-
- public MetaMessage() {
- super(new byte[] {-1, 0});
- }
-
- protected MetaMessage(byte[] data) {
- super(data);
- if (data == null) {
- throw new NullPointerException();
- }
- if (super.length > 3) {
- int n = 3;
- while ((n <= super.length) && (super.data[n - 1] < 0)) {
- n++;
- }
- dsp = n;
- }
- }
-
- @Override
- public Object clone() {
- return new MetaMessage(this.getMessage());
- }
-
- public byte[] getData() {
- if ((super.data != null) && (super.length > 3)) {
- byte[] bt = new byte[super.length - dsp];
- for (int i = dsp; i < super.length; i++) {
- bt[i - dsp] = super.data[i];
- }
- return bt;
- }
- return new byte[0];
- }
-
- public int getType() {
- if ((super.data != null) && (super.length >= 2)) {
- return super.data[1] & 0xFF;
- }
- return 0;
- }
-
- public void setMessage(int type, byte[] data, int length) throws InvalidMidiDataException {
- if (type < 0 || type >= 128) {
- // sound.0A=Invalid meta event with type {0}
- throw new InvalidMidiDataException(Messages.getString("sound.0A", type)); //$NON-NLS-1$
- }
- if (length < 0 || (data != null && length > data.length)) {
- // sound.03=length out of bounds: {0}
- throw new InvalidMidiDataException(Messages.getString("sound.03", length)); //$NON-NLS-1$
- }
- try {
- if (data == null) {
- if (length != 0) {
- throw new NullPointerException();
- }
- super.setMessage(new byte[] { -1, (byte) type, 0 }, 3);
- } else {
- int div = 128;
- int n = 1;
- int ost;
- int sm = 0;
- while (length / div != 0) {
- n++;
- div *= 128;
- }
- int ln = n;
- byte[] tdata = new byte[length + ln + 2];
- div = 1;
- ost = (length / div) % 128;
- while (n != 0) {
- tdata[n - 1 + 2] = (byte) (ost + sm);
- n--;
- div *= 128;
- ost = (length / div) % 128;
- sm = 128;
- }
- tdata[0] = -1;
- tdata[1] = (byte) type;
- if (length > 0) {
- for (int i = 0; i < length; i++) {
- tdata[2 + ln + i] = data[i];
- }
- }
- super.setMessage(tdata, length + 2 + ln);
- dsp = ln + 2;
- }
- } catch (InvalidMidiDataException e) {
- throw e;
- }
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiChannel.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiChannel.java
deleted file mode 100644
index e970641..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiChannel.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public interface MidiChannel {
- void allNotesOff();
-
- void allSoundOff();
-
- void controlChange(int controller, int value);
-
- int getChannelPressure();
-
- int getController(int controller);
-
- boolean getMono();
-
- boolean getMute();
-
- boolean getOmni();
-
- int getPitchBend();
-
- int getPolyPressure(int noteNumber);
-
- int getProgram();
-
- boolean getSolo();
-
- boolean localControl(boolean on);
-
- void noteOff(int noteNumber);
-
- void noteOff(int noteNumber, int velocity);
-
- void noteOn(int noteNumber, int velocity);
-
- void programChange(int program);
-
- void programChange(int bank, int program);
-
- void resetAllControllers();
-
- void setChannelPressure(int pressure);
-
- void setMono(boolean on);
-
- void setMute(boolean mute);
-
- void setOmni(boolean on);
-
- void setPitchBend(int bend);
-
- void setPolyPressure(int noteNumber, int pressure);
-
- void setSolo(boolean soloState);
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiDevice.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiDevice.java
deleted file mode 100644
index 9eb5169..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiDevice.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.List;
-
-public interface MidiDevice {
- class Info {
- private String name;
-
- private String vendor;
-
- private String description;
-
- private String version;
-
- protected Info(String name, String vendor, String description, String version) {
- this.name = name;
- this.vendor = vendor;
- this.description = description;
- this.version = version;
- }
-
- /*
- * returns true when objects are the same
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public final boolean equals(Object obj) {
- return this == obj;
- }
-
- public final String getDescription() {
- return description;
- }
-
- public final String getName() {
- return name;
- }
-
- public final String getVendor() {
- return vendor;
- }
-
- public final String getVersion() {
- return version;
- }
-
- @Override
- public final int hashCode() {
- final int PRIME = 31;
- int result = super.hashCode();
- result = PRIME * result + ((description == null) ? 0 : description.hashCode());
- result = PRIME * result + ((name == null) ? 0 : name.hashCode());
- result = PRIME * result + ((vendor == null) ? 0 : vendor.hashCode());
- result = PRIME * result + ((version == null) ? 0 : version.hashCode());
- return result;
- }
-
- @Override
- public final String toString() {
- return name;
- }
- }
-
- void close();
-
- MidiDevice.Info getDeviceInfo();
-
- int getMaxReceivers();
-
- int getMaxTransmitters();
-
- long getMicrosecondPosition();
-
- Receiver getReceiver() throws MidiUnavailableException;
-
- List<Receiver> getReceivers();
-
- Transmitter getTransmitter() throws MidiUnavailableException;
-
- List<Transmitter> getTransmitters();
-
- boolean isOpen();
-
- void open() throws MidiUnavailableException;
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiEvent.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiEvent.java
deleted file mode 100644
index 145529b..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiEvent.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-public class MidiEvent {
- private MidiMessage message;
-
- private long tick;
-
- public MidiEvent(MidiMessage message, long tick) {
- this.message = message;
- this.tick = tick;
- }
-
- public MidiMessage getMessage() {
- return message;
- }
-
- public long getTick() {
- return tick;
- }
-
- public void setTick(long tick) {
- this.tick = tick;
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiFileFormat.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiFileFormat.java
deleted file mode 100644
index e4e9498..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiFileFormat.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-public class MidiFileFormat {
- public static final int UNKNOWN_LENGTH = -1;
-
- protected int byteLength;
-
- protected float divisionType;
-
- protected long microsecondLength;
-
- protected int resolution;
-
- protected int type;
-
- private HashMap<String, Object> properties;
-
- public MidiFileFormat(int type, float divisionType, int resolution, int bytes,
- long microseconds) {
- this.type = type;
- this.divisionType = divisionType;
- this.resolution = resolution;
- this.byteLength = bytes;
- this.microsecondLength = microseconds;
- this.properties = new HashMap<String, Object>();
- }
-
- public MidiFileFormat(int type, float divisionType, int resolution, int bytes,
- long microseconds, Map<String, Object> properties) {
- this.type = type;
- this.divisionType = divisionType;
- this.resolution = resolution;
- this.byteLength = bytes;
- this.microsecondLength = microseconds;
-
- this.properties = new HashMap<String, Object>();
- this.properties.putAll(properties);
- }
-
- public int getByteLength() {
- return byteLength;
- }
-
- public float getDivisionType() {
- return divisionType;
- }
-
- public long getMicrosecondLength() {
- return microsecondLength;
- }
-
- public Object getProperty(String key) {
- return properties.get(key);
- }
-
- public int getResolution() {
- return resolution;
- }
-
- public int getType() {
- return type;
- }
-
- public Map<String, Object> properties() {
- return Collections.unmodifiableMap(properties);
-
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiMessage.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiMessage.java
deleted file mode 100644
index 1629ee1..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiMessage.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import org.apache.harmony.sound.internal.nls.Messages;
-
-public abstract class MidiMessage implements Cloneable {
-
- protected byte[] data;
-
- protected int length;
-
- protected MidiMessage(byte[] data) {
- if (data == null) {
- length = 0;
- } else {
- length = data.length;
- this.data = data;
- }
- }
-
- @Override
- public abstract Object clone();
-
- public int getLength() {
- return length;
- }
-
- public byte[] getMessage() {
- if (data == null) {
- throw new NullPointerException();
- }
- return data.clone();
- }
-
- public int getStatus() {
- if ((data == null) || (length == 0)) {
- return 0;
- }
- return data[0] & 0xFF;
- }
-
- protected void setMessage(byte[] data, int length) throws InvalidMidiDataException {
- if ((length < 0) || (length > data.length)) {
- // sound.03=length out of bounds: {0}
- throw new IndexOutOfBoundsException(Messages.getString("sound.03", length)); //$NON-NLS-1$
- }
-
- this.data = new byte[length];
- if (length != 0) {
- for (int i = 0; i < length; i++) {
- this.data[i] = data[i];
- }
- }
- this.length = length;
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiSystem.java b/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiSystem.java
deleted file mode 100644
index eede0a9..0000000
--- a/libcore-disabled/sound/src/main/java/javax/sound/midi/MidiSystem.java
+++ /dev/null
@@ -1,837 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package javax.sound.midi;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URL;
-
-import javax.sound.midi.MidiDevice.Info;
-import javax.sound.midi.spi.MidiDeviceProvider;
-import javax.sound.midi.spi.MidiFileReader;
-import javax.sound.midi.spi.MidiFileWriter;
-import javax.sound.midi.spi.SoundbankReader;
-
-import org.apache.harmony.sound.utils.ProviderService;
-
-public class MidiSystem {
- //path to javax.sound.midi.spi.MidiDeviceProvider file in the jar-file
- private final static String midiDeviceProviderPath =
- "META-INF/services/javax.sound.midi.spi.MidiDeviceProvider";
-
- //path to javax.sound.midi.spi.MidiFileReader file in the jar-file
- private final static String midiFileReaderPath =
- "META-INF/services/javax.sound.midi.spi.MidiFileReader";
-
- //path to javax.sound.midi.spi.MidiFileWriter file in the jar-file
- private final static String midiFileWriterPath =
- "META-INF/services/javax.sound.midi.spi.MidiFileWriter";
-
- //path to javax.sound.midi.spi.SoundbankReader file in the jar-file
- private final static String soundbankReaderPath =
- "META-INF/services/javax.sound.midi.spi.SoundbankReader";
-
- //key to find default receiver in the sound.properties file
- private final static String receiverName = "javax.sound.midi.Receiver";
-
- //key to find default sequencer in the sound.properties file
- private final static String sequencerName = "javax.sound.midi.Sequencer";
-
- //key to find default synthesizer in the sound.properties file
- private final static String synthesizerName = "javax.sound.midi.Synthesizer";
-
- //key to find default transmitter in the sound.properties file
- private final static String transmitterName = "javax.sound.midi.Transmitter";
-
- public static MidiDevice getMidiDevice(MidiDevice.Info info)
- throws MidiUnavailableException {
- //FIXME
- /*
- * this method must to throw out MidiUnavailableException if requested device
- * is not available
- */
-
- /*
- * obtain the list of MidiDeviceProviders
- */
- List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
- /*
- * find device that describes by parameter info and return it
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.equals(info)) {
- return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(info);
- }
- }
- }
- /*
- * if we can't find device with requested info, we throw out IllegalArgumentException
- */
- throw new IllegalArgumentException("Requested device not installed: " + info.getName());
- }
-
- public static MidiDevice.Info[] getMidiDeviceInfo() {
- /*
- * obtain the list of MidiDeviceProviders
- */
- List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
- //variable to save MidiDevice.Info
- List<MidiDevice.Info> infos = new ArrayList<MidiDevice.Info>();
- /*
- * look through list of providers and save info of devices
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- infos.add(element);
- }
- }
-
- MidiDevice.Info[] temp = new MidiDevice.Info[infos.size()];
- return infos.toArray(temp);
- }
-
- public static MidiFileFormat getMidiFileFormat(File file) throws InvalidMidiDataException,
- IOException {
- /*
- * obtain the list of MidiFileReaderProviders
- */
- List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
- if (fileReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileReader) fileReaderProviders.get(0)).getMidiFileFormat(file);
- }
-
- public static MidiFileFormat getMidiFileFormat(InputStream stream) throws InvalidMidiDataException,
- IOException {
- /*
- * obtain the list of MidiFileReaderProviders
- */
- List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
- if (fileReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileReader) fileReaderProviders.get(0)).getMidiFileFormat(stream);
- }
-
- public static MidiFileFormat getMidiFileFormat(URL url) throws InvalidMidiDataException,
- IOException {
- /*
- * obtain the list of MidiFileReaderProviders
- */
- List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
- if (fileReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileReader) fileReaderProviders.get(0)).getMidiFileFormat(url);
- }
-
- public static int[] getMidiFileTypes() {
- /*
- * obtain the list of MidiFileWriterProviders
- */
- List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
- if (fileWriterProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileWriterProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileWriter) fileWriterProviders.get(0)).getMidiFileTypes();
- }
-
- public static int[] getMidiFileTypes(Sequence sequence) {
- /*
- * obtain the list of MidiFileWriterProviders
- */
- List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
- if (fileWriterProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileWriterProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileWriter) fileWriterProviders.get(0)).getMidiFileTypes(sequence);
- }
-
- public static Receiver getReceiver() throws MidiUnavailableException {
- /*
- * description of the default device for javax.sound.midi.Receiver
- */
- List<String> defaultDevice = ProviderService.getDefaultDeviceDescription(receiverName);
- /*
- * obtain the list of MidiDeviceProviders
- */
- List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
- String provName;
- int deviceNum = -1;
- /*
- * defaultDevice.get(0) --> provider
- * defaultDevice.get(1) --> name
- */
- if (defaultDevice.size() != 0) {
- /*
- * obtain the provider number in the list of deviceProviders that is provider for default device
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- provName = deviceProviders.get(i).toString();
- if (provName.substring(0, provName.indexOf("@")).equals(defaultDevice.get(0))) {
- deviceNum = i;
- break;
- }
- }
- /*
- * the first case: find the same provider and name that describes by default device
- */
- if (deviceNum != -1) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element).getReceiver();
- } catch (MidiUnavailableException e) {}
- }
- }
- for (Info element : deviceInfo) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element).getReceiver();
- } catch (MidiUnavailableException e) {}
- }
- }
- /*
- * if we don't find again, find any receivers describe by name
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element).getReceiver();
- } catch (MidiUnavailableException e) {}
- }
- }
- }
- }
- /*
- * in the last case we look throw all providers and find any receiver
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element).getReceiver();
- } catch (MidiUnavailableException e) {}
- }
- }
- /*
- * if we don't find anyway, we throw out MidiUnavailableException
- */
- throw new MidiUnavailableException("There are no Recivers installed on your system!");
- }
-
- public static Sequence getSequence(File file) throws InvalidMidiDataException, IOException {
- /*
- * obtain the list of MidiFileReaderProviders
- */
- List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
- // BEGIN android-added
- try {
- ((List)fileReaderProviders).add((Object)Class.forName("com.android.internal.sound.midi.AndroidMidiFileReader").newInstance());
- } catch (Exception ex) {
- // Ignore
- }
- // END android-added
- if (fileReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileReader) fileReaderProviders.get(0)).getSequence(file);
- }
-
- public static Sequence getSequence(InputStream stream) throws InvalidMidiDataException,
- IOException {
- /*
- * obtain the list of MidiFileReaderProviders
- */
- List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
- // BEGIN android-added
- try {
- ((List)fileReaderProviders).add(Class.forName("com.android.internal.sound.midi.AndroidMidiFileReader").newInstance());
- } catch (Exception ex) {
- // Ignore
- }
- // END android-added
- if (fileReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileReader) fileReaderProviders.get(0)).getSequence(stream);
- }
-
- public static Sequence getSequence(URL url) throws InvalidMidiDataException, IOException {
- /*
- * obtain the list of MidiFileReaderProviders
- */
- List<?> fileReaderProviders = ProviderService.getProviders(midiFileReaderPath);
- // BEGIN android-added
- try {
- ((List)fileReaderProviders).add(Class.forName("com.android.internal.sound.midi.AndroidMidiFileReader").newInstance());
- } catch (Exception ex) {
- // Ignore
- }
- // END android-added
- if (fileReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileReader) fileReaderProviders.get(0)).getSequence(url);
- }
-
- public static Sequencer getSequencer() throws MidiUnavailableException {
- /*
- * this method is equals to method MidiSystem.getSequencer(true)
- */
- return getSequencer(true);
- }
-
- public static Sequencer getSequencer(boolean connected) throws MidiUnavailableException {
- /*
- * description of the default device for javax.sound.midi.Sequencer
- */
- List<String> defaultDevice = ProviderService.getDefaultDeviceDescription(sequencerName);
- /*
- * obtain the list of MidiDeviceProviders
- */
- List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
-
- Sequencer sequencer;
- Transmitter seqTrans;
- Synthesizer synth;
- Receiver recv;
- String provName;
- int deviceNum = -1;
- /*
- * defaultDevice.get(0) --> provider
- * defaultDevice.get(1) --> name
- */
- if (defaultDevice.size() != 0) {
- /*
- * obtain the provider number in the list of deviceProviders that is provider for default device
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- provName = deviceProviders.get(i).toString();
- if (provName.substring(0, provName.indexOf("@")).equals(defaultDevice.get(0))) {
- deviceNum = i;
- break;
- }
- }
- /*
- * the first case: find the same provider and name that describes by default device
- */
- if (deviceNum != -1) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- if (((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element) instanceof Sequencer) {
- if (connected) {
- sequencer = (Sequencer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
- seqTrans = sequencer.getTransmitter();
- try {
- synth = MidiSystem.getSynthesizer();
- recv = synth.getReceiver();
- } catch (MidiUnavailableException e) {
- /*
- * if we haven't Synthesizer in the system, we use default receiver
- */
- recv = MidiSystem.getReceiver();
- }
- seqTrans.setReceiver(recv);
- return sequencer;
- }
- return (Sequencer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
- }
- }
- }
- for (Info element : deviceInfo) {
- if (((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element) instanceof Sequencer) {
- if (connected) {
- sequencer = (Sequencer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
- seqTrans = sequencer.getTransmitter();
- try {
- synth = MidiSystem.getSynthesizer();
- recv = synth.getReceiver();
- } catch (MidiUnavailableException e) {
- /*
- * if we haven't Synthesizer in the system, we use default receiver
- */
- recv = MidiSystem.getReceiver();
- }
- seqTrans.setReceiver(recv);
- return sequencer;
- }
- return (Sequencer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
- }
- }
- }
- /*
- * if we don't find again, find any receivers describe by name
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- if (((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element) instanceof Sequencer) {
- if (connected) {
- sequencer = (Sequencer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
- seqTrans = sequencer.getTransmitter();
- try {
- synth = MidiSystem.getSynthesizer();
- recv = synth.getReceiver();
- } catch (MidiUnavailableException e) {
- /*
- * if we haven't Synthesizer in the system, we use default receiver
- */
- recv = MidiSystem.getReceiver();
- }
- seqTrans.setReceiver(recv);
- return sequencer;
- }
- return (Sequencer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
- }
- }
- }
- }
- }
- /*
- * in the last case we look throw all providers and find any receiver
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element) instanceof Sequencer) {
- if (connected) {
- sequencer = (Sequencer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
- seqTrans = sequencer.getTransmitter();
- try {
- synth = MidiSystem.getSynthesizer();
- recv = synth.getReceiver();
- } catch (MidiUnavailableException e) {
- /*
- * if we haven't Synthesizer in the system, we use default receiver
- */
- recv = MidiSystem.getReceiver();
- }
- seqTrans.setReceiver(recv);
- return sequencer;
- }
- return (Sequencer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
- }
- }
- }
- // BEGIN android-added
- try {
- return (Sequencer)(Class.forName("com.android.internal.sound.midi.AndroidSequencer").newInstance());
- } catch (Exception ex) {
- // Ignore
- }
- // END android-added
- /*
- * if we don't find anyway, we throw out MidiUnavailableException
- */
- throw new MidiUnavailableException("There are no Synthesizers installed on your system!");
- }
-
- public static Soundbank getSoundbank(File file) throws InvalidMidiDataException,
- IOException {
- /*
- * obtain the list of SoundbankReaderProviders
- */
- List<?> soundbankReaderProviders = ProviderService.getProviders(soundbankReaderPath);
- if (soundbankReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no SoundbankReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((SoundbankReader) soundbankReaderProviders.get(0)).getSoundbank(file);
- }
-
- public static Soundbank getSoundbank(InputStream stream) throws InvalidMidiDataException, IOException {
- /*
- * obtain the list of SoundbankReaderProviders
- */
- List<?> soundbankReaderProviders = ProviderService.getProviders(soundbankReaderPath);
- if (soundbankReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no SoundbankReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((SoundbankReader) soundbankReaderProviders.get(0)).getSoundbank(stream);
- }
-
- public static Soundbank getSoundbank(URL url) throws InvalidMidiDataException, IOException {
- /*
- * obtain the list of SoundbankReaderProviders
- */
- List<?> soundbankReaderProviders = ProviderService.getProviders(soundbankReaderPath);
- if (soundbankReaderProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no SoundbankReaderProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((SoundbankReader) soundbankReaderProviders.get(0)).getSoundbank(url);
- }
-
- public static Synthesizer getSynthesizer() throws MidiUnavailableException {
- /*
- * description of the default device for javax.sound.midi.Synthesizer
- */
- List<String> defaultDevice = ProviderService.getDefaultDeviceDescription(synthesizerName);
- /*
- * obtain the list of MidiDeviceProviders
- */
- List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
- String provName;
- int deviceNum = -1;
-
- /*
- * defaultDevice.get(0) --> provider
- * defaultDevice.get(1) --> name
- */
- if (defaultDevice.size() != 0) {
- /*
- * obtain the provider number in the list of deviceProviders that is provider for default device
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- provName = deviceProviders.get(i).toString();
- if (provName.substring(0, provName.indexOf("@")).equals(defaultDevice.get(0))) {
- deviceNum = i;
- break;
- }
- }
- /*
- * the first case: find the same provider and name that describes by default device
- */
- if (deviceNum != -1) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- if (((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element) instanceof Synthesizer) {
- return (Synthesizer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
- }
- }
- }
- for (Info element : deviceInfo) {
- if (((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element) instanceof Synthesizer) {
- return (Synthesizer) ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element);
- }
- }
- }
- /*
- * if we don't find again, find any receivers describe by name
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- if (((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element) instanceof Synthesizer) {
- return (Synthesizer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
- }
- }
- }
- }
- }
- /*
- * in the last case we look throw all providers and find any receiver
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element) instanceof Synthesizer) {
- return (Synthesizer) ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element);
- }
- }
- }
- /*
- * if we don't find anyway, we throw out MidiUnavailableException
- */
- throw new MidiUnavailableException("There are no Synthesizers installed on your system!");
- }
-
- public static Transmitter getTransmitter() throws MidiUnavailableException {
- /*
- * description of the default device for javax.sound.midi.Transmitter
- */
- List<String> defaultDevice = ProviderService.getDefaultDeviceDescription(transmitterName);
- /*
- * obtain the list of MidiDeviceProviders
- */
- List<?> deviceProviders = ProviderService.getProviders(midiDeviceProviderPath);
- String provName;
- int deviceNum = -1;
- /*
- * defaultDevice.get(0) --> provider
- * defaultDevice.get(1) --> name
- */
- if (defaultDevice.size() != 0) {
- /*
- * obtain the provider number in the list of deviceProviders that is provider for default device
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- provName = deviceProviders.get(i).toString();
- if (provName.substring(0, provName.indexOf("@")).equals(defaultDevice.get(0))) {
- deviceNum = i;
- break;
- }
- }
- /*
- * the first case: find the same provider and name that describes by default device
- */
- if (deviceNum != -1) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element).getTransmitter();
- } catch (MidiUnavailableException e) {}
- }
- }
- for (Info element : deviceInfo) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(deviceNum)).getDevice(element).getTransmitter();
- } catch (MidiUnavailableException e) {}
- }
- }
- /*
- * if we don't find again, find any receivers describe by name
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- if (element.getName().equals(defaultDevice.get(1))) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element).getTransmitter();
- } catch (MidiUnavailableException e) {}
- }
- }
- }
- }
- /*
- * in the last case we look throw all providers and find any receiver
- */
- for (int i = 0; i < deviceProviders.size(); i++) {
- MidiDevice.Info[] deviceInfo = ((MidiDeviceProvider) deviceProviders.get(i)).getDeviceInfo();
- for (Info element : deviceInfo) {
- try {
- return ((MidiDeviceProvider) deviceProviders.get(i)).getDevice(element).getTransmitter();
- } catch (MidiUnavailableException e) {}
- }
- }
- /*
- * if we don't find anyway, we throw out MidiUnavailableException
- */
- throw new MidiUnavailableException("There are no Transmitters installed on your system!");
- }
-
- public static boolean isFileTypeSupported(int fileType) {
- /*
- * obtain the list of MidiFileWriterProviders;
- * if we already obtain the list of providers, we don't obtain it again
- */
- List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
- if (fileWriterProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileWriterProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileWriter) fileWriterProviders.get(0)).isFileTypeSupported(fileType);
- }
-
- public static boolean isFileTypeSupported(int fileType, Sequence sequence) {
- /*
- * obtain the list of MidiFileWriterProviders
- */
- List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
- if (fileWriterProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileWriterProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileWriter) fileWriterProviders.get(0)).isFileTypeSupported(fileType, sequence);
- }
-
- public static int write(Sequence in, int type, File out) throws IOException {
- /*
- * obtain the list of MidiFileWriterProviders
- */
- List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
- if (fileWriterProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileWriterProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileWriter) fileWriterProviders.get(0)).write(in, type, out);
- }
-
- public static int write(Sequence in, int fileType, OutputStream out) throws IOException {
- /*
- * obtain the list of MidiFileWriterProviders
- */
- List<?> fileWriterProviders = ProviderService.getProviders(midiFileWriterPath);
- if (fileWriterProviders.size() == 0) {
- //FIXME
- /*
- * I don't understand what type of exception we should throw out if we haven't
- * appropriate providers...
- * Maybe here is should be MidiUnavailableException
- */
- throw new Error("There is no MidiFileWriterProviders on your system!!!");
- }
- /*
- * It's not determine what provider for this service I should to use, and so
- * I use the first one
- */
- return ((MidiFileWriter) fileWriterProviders.get(0)).write(in, fileType, out);
- }
-}
diff --git a/libcore-disabled/sound/src/main/java/javax/sound/midi/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> <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> <small>(comma)</small> elision.</li>
- * <li>Strings may be quoted with <code>'</code> <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> <small>(left bracket)</small>
- * and ends with <code>]</code> <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> <small>(left bracket)</small> and ending
- * with <code>]</code> <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> <small>(comma)</small> may appear just
- * before the closing brace.</li>
- * <li>Strings may be quoted with <code>'</code> <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> <small>(left brace)</small> and ending
- * with <code>}</code> <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 </, 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> <small>(left brace)</small> and ending
- * with <code>}</code> <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> <small>(left brace)</small> and ending
- * with <code>}</code> <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> <small>(left brace)</small> and ending
- * with <code>}</code> <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> <small>(left brace)</small> and ending
- * with <code>}</code> <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> <small>(left brace)</small> and ending
- * with <code>}</code> <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> <small>(double quote)</small> or
- * <code>'</code> <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 < 0, start < 0</code> or
+ * <code>start + length > 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], ×) == 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);
}
}
-