--- a/jdk/make/com/sun/servicetag/Makefile Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/make/com/sun/servicetag/Makefile Mon Sep 12 16:59:34 2011 -0700
@@ -47,7 +47,7 @@
# Add all properties files to the FILES_copy list
SWORDFISH_properties := $(shell \
$(CD) $(SHARE_SRC)/classes/com/sun/servicetag/resources; \
- $(FIND) . -name 'javase_*_swordfish.properties' -print ; \
+ $(FIND) . -name 'javase_*.properties' -print ; \
)
FILES_copy += $(shell \
for f in $(SWORDFISH_properties) ; do \
--- a/jdk/make/jprt.properties Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/make/jprt.properties Mon Sep 12 16:59:34 2011 -0700
@@ -258,6 +258,15 @@
windows_i586_5.1-product-c1-jdk_security3, \
windows_x64_5.2-product-c2-jdk_security3, \
\
+ solaris_sparc_5.10-product-c1-jdk_sound, \
+ solaris_sparcv9_5.10-product-c2-jdk_sound, \
+ solaris_i586_5.10-product-c1-jdk_sound, \
+ solaris_x64_5.10-product-c2-jdk_sound, \
+ linux_i586_2.6-product-{c1|c2}-jdk_sound, \
+ linux_x64_2.6-product-c2-jdk_sound, \
+ windows_i586_5.1-product-c1-jdk_sound, \
+ windows_x64_5.2-product-c2-jdk_sound, \
+ \
solaris_sparc_5.10-product-c1-jdk_swing, \
solaris_sparcv9_5.10-product-c2-jdk_swing, \
solaris_i586_5.10-product-c1-jdk_swing, \
--- a/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JFIFMarkerSegment.java Mon Sep 12 16:59:34 2011 -0700
@@ -763,7 +763,7 @@
}
} catch (IllegalThumbException e) {
// Should never happen
- throw new InternalError("Illegal thumb in setThumbnail!");
+ throw new InternalError("Illegal thumb in setThumbnail!", e);
}
}
--- a/jdk/src/share/classes/com/sun/jmx/snmp/SnmpCounter64.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/SnmpCounter64.java Mon Sep 12 16:59:34 2011 -0700
@@ -186,7 +186,7 @@
newclone = (SnmpCounter64) super.clone() ;
newclone.value = value ;
} catch (CloneNotSupportedException e) {
- throw new InternalError() ; // vm bug.
+ throw new InternalError(e) ; // vm bug.
}
return newclone ;
}
--- a/jdk/src/share/classes/com/sun/jmx/snmp/SnmpInt.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/SnmpInt.java Mon Sep 12 16:59:34 2011 -0700
@@ -232,7 +232,7 @@
newclone = (SnmpInt) super.clone() ;
newclone.value = value ;
} catch (CloneNotSupportedException e) {
- throw new InternalError() ; // vm bug.
+ throw new InternalError(e) ; // vm bug.
}
return newclone ;
}
--- a/jdk/src/share/classes/com/sun/jmx/snmp/SnmpNull.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/SnmpNull.java Mon Sep 12 16:59:34 2011 -0700
@@ -129,7 +129,7 @@
newclone = (SnmpNull) super.clone() ;
newclone.tag = tag ;
} catch (CloneNotSupportedException e) {
- throw new InternalError() ; // vm bug.
+ throw new InternalError(e) ; // vm bug.
}
return newclone ;
}
--- a/jdk/src/share/classes/com/sun/jmx/snmp/SnmpString.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/SnmpString.java Mon Sep 12 16:59:34 2011 -0700
@@ -250,7 +250,7 @@
newclone.value = new byte[value.length] ;
System.arraycopy(value, 0, newclone.value, 0, value.length) ;
} catch (CloneNotSupportedException e) {
- throw new InternalError() ; // vm bug.
+ throw new InternalError(e) ; // vm bug.
}
return newclone ;
}
--- a/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpRequestHandler.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/snmp/daemon/SnmpRequestHandler.java Mon Sep 12 16:59:34 2011 -0700
@@ -921,7 +921,7 @@
SNMP_ADAPTOR_LOGGER.logp(Level.FINEST, dbgTag,
"newTooBigMessage", "Internal error", x);
}
- throw new InternalError() ;
+ throw new InternalError(x) ;
}
return result ;
--- a/jdk/src/share/classes/com/sun/security/auth/module/NTSystem.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/com/sun/security/auth/module/NTSystem.java Mon Sep 12 16:59:34 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
public class NTSystem {
private native void getCurrent(boolean debug);
+ private native long getImpersonationToken0();
private String userName;
private String domain;
@@ -132,10 +133,14 @@
*
* @return an impersonation token for the current NT user.
*/
- public long getImpersonationToken() {
+ public synchronized long getImpersonationToken() {
+ if (impersonationToken == 0) {
+ impersonationToken = getImpersonationToken0();
+ }
return impersonationToken;
}
+
private void loadNative() {
System.loadLibrary("jaas_nt");
}
--- a/jdk/src/share/classes/com/sun/servicetag/BrowserSupport.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/com/sun/servicetag/BrowserSupport.java Mon Sep 12 16:59:34 2011 -0700
@@ -77,9 +77,7 @@
result = (Boolean) isDesktopSupportedMethod.invoke(null);
} catch (IllegalAccessException e) {
// should never reach here
- InternalError x =
- new InternalError("Desktop.getDesktop() method not found");
- x.initCause(e);
+ throw new InternalError("Desktop.getDesktop() method not found", e);
} catch (InvocationTargetException e) {
// browser not supported
if (Util.isVerbose()) {
@@ -101,28 +99,10 @@
result = (Boolean) isSupportedMethod.invoke(desktopObj, browseField.get(null));
supported = result.booleanValue();
}
- } catch (ClassNotFoundException e) {
- // browser not supported
- if (Util.isVerbose()) {
- e.printStackTrace();
- }
- } catch (NoSuchMethodException e) {
- // browser not supported
- if (Util.isVerbose()) {
- e.printStackTrace();
- }
- } catch (NoSuchFieldException e) {
- // browser not supported
- if (Util.isVerbose()) {
- e.printStackTrace();
- }
} catch (IllegalAccessException e) {
// should never reach here
- InternalError x =
- new InternalError("Desktop.getDesktop() method not found");
- x.initCause(e);
- throw x;
- } catch (InvocationTargetException e) {
+ throw new InternalError("Desktop.getDesktop() method not found", e);
+ } catch (ReflectiveOperationException e) {
// browser not supported
if (Util.isVerbose()) {
e.printStackTrace();
@@ -175,10 +155,7 @@
browseMethod.invoke(desktop, uri);
} catch (IllegalAccessException e) {
// should never reach here
- InternalError x =
- new InternalError("Desktop.getDesktop() method not found");
- x.initCause(e);
- throw x;
+ throw new InternalError("Desktop.getDesktop() method not found", e);
} catch (InvocationTargetException e) {
Throwable x = e.getCause();
if (x != null) {
--- a/jdk/src/share/classes/com/sun/servicetag/Installer.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/com/sun/servicetag/Installer.java Mon Sep 12 16:59:34 2011 -0700
@@ -61,8 +61,8 @@
private static RegistrationData registration;
private static boolean supportRegistration;
private static String registerHtmlParent;
- private static Set<Locale> supportedLocales = new HashSet<Locale>();
- private static Properties swordfishProps = null;
+ private static Set<Locale> supportedLocales = new HashSet<>();
+ private static Properties svcTagProps = null;
private static String[] jreArchs = null;
static {
String dir = System.getProperty(SVCTAG_DIR_PATH);
@@ -94,7 +94,7 @@
boolean cleanup = false;
try {
// Check if we have the swordfish entries for this JRE version
- if (loadSwordfishEntries() == null) {
+ if (loadServiceTagProps() == null) {
return null;
}
@@ -144,18 +144,14 @@
return registration;
}
if (regXmlFile.exists()) {
- BufferedInputStream in = null;
- try {
- in = new BufferedInputStream(new FileInputStream(regXmlFile));
+ try (BufferedInputStream in =
+ new BufferedInputStream(new FileInputStream(regXmlFile)))
+ {
registration = RegistrationData.loadFromXML(in);
} catch (IllegalArgumentException ex) {
System.err.println("Error: Bad registration data \"" +
regXmlFile + "\":" + ex.getMessage());
throw ex;
- } finally {
- if (in != null) {
- in.close();
- }
}
} else {
registration = new RegistrationData();
@@ -186,18 +182,14 @@
deleteRegistrationHtmlPage();
getRegistrationHtmlPage();
- BufferedOutputStream out = null;
- try {
- out = new BufferedOutputStream(new FileOutputStream(regXmlFile));
+ try (BufferedOutputStream out =
+ new BufferedOutputStream(new FileOutputStream(regXmlFile)))
+ {
getRegistrationData().storeToXML(out);
} catch (IllegalArgumentException ex) {
System.err.println("Error: Bad registration data \"" +
regXmlFile + "\":" + ex.getMessage());
throw ex;
- } finally {
- if (out != null) {
- out.close();
- }
}
}
@@ -206,11 +198,9 @@
* or empty set if file not exists.
*/
private static Set<String> getInstalledURNs() throws IOException {
- Set<String> urnSet = new HashSet<String>();
+ Set<String> urnSet = new HashSet<>();
if (serviceTagFile.exists()) {
- BufferedReader in = null;
- try {
- in = new BufferedReader(new FileReader(serviceTagFile));
+ try (BufferedReader in = new BufferedReader(new FileReader(serviceTagFile))) {
String urn;
while ((urn = in.readLine()) != null) {
urn = urn.trim();
@@ -218,10 +208,6 @@
urnSet.add(urn);
}
}
- } finally {
- if (in != null) {
- in.close();
- }
}
}
return urnSet;
@@ -237,9 +223,9 @@
private static ServiceTag[] getJavaServiceTagArray() throws IOException {
RegistrationData regData = getRegistrationData();
Set<ServiceTag> svcTags = regData.getServiceTags();
- Set<ServiceTag> result = new HashSet<ServiceTag>();
+ Set<ServiceTag> result = new HashSet<>();
- Properties props = loadSwordfishEntries();
+ Properties props = loadServiceTagProps();
String jdkUrn = props.getProperty("servicetag.jdk.urn");
String jreUrn = props.getProperty("servicetag.jre.urn");
for (ServiceTag st : svcTags) {
@@ -343,8 +329,7 @@
}
private static ServiceTag newServiceTag(String svcTagSource) throws IOException {
- // Load the swoRDFish information for the service tag creation
- Properties props = loadSwordfishEntries();
+ Properties props = loadServiceTagProps();
// Determine the product URN and name
String productURN;
@@ -442,52 +427,35 @@
return;
}
- PrintWriter out = null;
- try {
- out = new PrintWriter(serviceTagFile);
-
+ try (PrintWriter out = new PrintWriter(serviceTagFile)) {
ServiceTag[] javaSvcTags = getJavaServiceTagArray();
for (ServiceTag st : javaSvcTags) {
// Write the instance_run to the servicetag file
String instanceURN = st.getInstanceURN();
out.println(instanceURN);
}
- } finally {
- if (out != null) {
- out.close();
- }
}
}
/**
- * Load the values associated with the swoRDFish metadata entries
- * for Java SE. The swoRDFish metadata entries are different for
- * different release.
+ * Load the properties for generating Java SE service tags.
*
* @param version Version of Java SE
*/
- private static synchronized Properties loadSwordfishEntries() throws IOException {
- if (swordfishProps != null) {
- return swordfishProps;
+ private static synchronized Properties loadServiceTagProps() throws IOException {
+ if (svcTagProps != null) {
+ return svcTagProps;
}
- // The version string for Java SE 6 is 1.6.0
- // We just need the minor number in the version string
- int version = Util.getJdkVersion();
-
- String filename = "/com/sun/servicetag/resources/javase_" +
- version + "_swordfish.properties";
- InputStream in = Installer.class.getResourceAsStream(filename);
- if (in == null) {
- return null;
+ // For Java SE 8 and later releases, JDK and JRE both use
+ // the same product number. The sworRDFish metadata were
+ // for legacy Sun part number.
+ String filename = "/com/sun/servicetag/resources/javase_servicetag.properties";
+ try (InputStream in = Installer.class.getResourceAsStream(filename)) {
+ svcTagProps = new Properties();
+ svcTagProps.load(in);
}
- swordfishProps = new Properties();
- try {
- swordfishProps.load(in);
- } finally {
- in.close();
- }
- return swordfishProps;
+ return svcTagProps;
}
/**
@@ -546,7 +514,7 @@
return jreArchs;
}
- Set<String> archs = new HashSet<String>();
+ Set<String> archs = new HashSet<>();
String os = System.getProperty("os.name");
if (os.equals("SunOS") || os.equals("Linux")) {
@@ -681,16 +649,16 @@
String country = locale.getCountry();
String variant = locale.getVariant();
- List<Locale> locales = new ArrayList<Locale>(3);
+ List<Locale> locales = new ArrayList<>(3);
if (variant.length() > 0) {
locales.add(locale);
}
if (country.length() > 0) {
- locales.add((locales.size() == 0) ?
+ locales.add((locales.isEmpty()) ?
locale : new Locale(language, country, ""));
}
if (language.length() > 0) {
- locales.add((locales.size() == 0) ?
+ locales.add((locales.isEmpty()) ?
locale : new Locale(language, "", ""));
}
return locales;
@@ -788,14 +756,11 @@
// Format the registration data in one single line
StringBuilder payload = new StringBuilder();
String xml = regData.toString().replaceAll("\"", "%22");
- BufferedReader reader = new BufferedReader(new StringReader(xml));
- try {
+ try (BufferedReader reader = new BufferedReader(new StringReader(xml))) {
String line = null;
while ((line = reader.readLine()) != null) {
payload.append(line.trim());
}
- } finally {
- reader.close();
}
String resourceFilename = "/com/sun/servicetag/resources/register";
--- a/jdk/src/share/classes/com/sun/servicetag/RegistrationDocument.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/com/sun/servicetag/RegistrationDocument.java Mon Sep 12 16:59:34 2011 -0700
@@ -150,9 +150,7 @@
} catch (ParserConfigurationException pce) {
// Parser with specific options can't be built
// should not reach here
- InternalError x = new InternalError("Error in creating the new document");
- x.initCause(pce);
- throw x;
+ throw new InternalError("Error in creating the new document", pce);
}
}
@@ -172,9 +170,7 @@
} catch (ParserConfigurationException pce) {
// Parser with specified options can't be built
// should not reach here
- InternalError x = new InternalError("Error in creating the new document");
- x.initCause(pce);
- throw x;
+ throw new InternalError("Error in creating the new document", pce);
}
}
@@ -195,20 +191,14 @@
new StreamResult(new BufferedWriter(new OutputStreamWriter(os, "UTF-8"))));
} catch (UnsupportedEncodingException ue) {
// Should not reach here
- InternalError x = new InternalError("Error generated during transformation");
- x.initCause(ue);
- throw x;
+ throw new InternalError("Error generated during transformation", ue);
} catch (TransformerConfigurationException tce) {
// Error generated by the parser
// Should not reach here
- InternalError x = new InternalError("Error in creating the new document");
- x.initCause(tce);
- throw x;
+ throw new InternalError("Error in creating the new document", tce);
} catch (TransformerException te) {
// Error generated by the transformer
- InternalError x = new InternalError("Error generated during transformation");
- x.initCause(te);
- throw x;
+ throw new InternalError("Error generated during transformation", te);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/servicetag/resources/javase_servicetag.properties Mon Sep 12 16:59:34 2011 -0700
@@ -0,0 +1,29 @@
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+
+servicetag.jdk.urn = Q8549
+servicetag.jdk.name = Java Development Kit
+servicetag.jre.urn = Q8549
+servicetag.jre.name = Java Runtime Environment
+servicetag.parent.urn = Q8549
+servicetag.parent.name = Java Platform, Standard Edition
--- a/jdk/src/share/classes/java/awt/BufferCapabilities.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/BufferCapabilities.java Mon Sep 12 16:59:34 2011 -0700
@@ -137,7 +137,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// Since we implement Cloneable, this should never happen
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/awt/Component.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/Component.java Mon Sep 12 16:59:34 2011 -0700
@@ -3776,11 +3776,10 @@
createBufferStrategy(numBuffers, bufferCaps);
return; // Success
} catch (AWTException e) {
- // Failed
- }
- // Code should never reach here (an unaccelerated blitting
- // strategy should always work)
- throw new InternalError("Could not create a buffer strategy");
+ // Code should never reach here (an unaccelerated blitting
+ // strategy should always work)
+ throw new InternalError("Could not create a buffer strategy", e);
+ }
}
/**
--- a/jdk/src/share/classes/java/awt/GridBagConstraints.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/GridBagConstraints.java Mon Sep 12 16:59:34 2011 -0700
@@ -653,7 +653,7 @@
return c;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/awt/ImageCapabilities.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/ImageCapabilities.java Mon Sep 12 16:59:34 2011 -0700
@@ -74,7 +74,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// Since we implement Cloneable, this should never happen
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/awt/Insets.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/Insets.java Mon Sep 12 16:59:34 2011 -0700
@@ -177,7 +177,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
/**
--- a/jdk/src/share/classes/java/awt/JobAttributes.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/JobAttributes.java Mon Sep 12 16:59:34 2011 -0700
@@ -361,7 +361,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// Since we implement Cloneable, this should never happen
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/awt/PageAttributes.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/PageAttributes.java Mon Sep 12 16:59:34 2011 -0700
@@ -969,7 +969,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// Since we implement Cloneable, this should never happen
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/awt/RenderingHints.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/RenderingHints.java Mon Sep 12 16:59:34 2011 -0700
@@ -1276,7 +1276,7 @@
}
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
return rh;
--- a/jdk/src/share/classes/java/awt/font/TextLayout.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/font/TextLayout.java Mon Sep 12 16:59:34 2011 -0700
@@ -753,7 +753,7 @@
return super.clone();
}
catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/awt/geom/AffineTransform.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/geom/AffineTransform.java Mon Sep 12 16:59:34 2011 -0700
@@ -3856,7 +3856,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/awt/geom/CubicCurve2D.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/geom/CubicCurve2D.java Mon Sep 12 16:59:34 2011 -0700
@@ -1569,7 +1569,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
}
--- a/jdk/src/share/classes/java/awt/geom/Dimension2D.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/geom/Dimension2D.java Mon Sep 12 16:59:34 2011 -0700
@@ -108,7 +108,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
}
--- a/jdk/src/share/classes/java/awt/geom/Line2D.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/geom/Line2D.java Mon Sep 12 16:59:34 2011 -0700
@@ -1122,7 +1122,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
}
--- a/jdk/src/share/classes/java/awt/geom/Point2D.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/geom/Point2D.java Mon Sep 12 16:59:34 2011 -0700
@@ -393,7 +393,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/awt/geom/QuadCurve2D.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/geom/QuadCurve2D.java Mon Sep 12 16:59:34 2011 -0700
@@ -1395,7 +1395,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
}
--- a/jdk/src/share/classes/java/awt/geom/RectangularShape.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/geom/RectangularShape.java Mon Sep 12 16:59:34 2011 -0700
@@ -391,7 +391,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
}
--- a/jdk/src/share/classes/java/awt/image/ImageFilter.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/image/ImageFilter.java Mon Sep 12 16:59:34 2011 -0700
@@ -252,7 +252,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
}
--- a/jdk/src/share/classes/java/awt/image/Kernel.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/awt/image/Kernel.java Mon Sep 12 16:59:34 2011 -0700
@@ -147,7 +147,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
}
--- a/jdk/src/share/classes/java/io/ObjectStreamClass.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/io/ObjectStreamClass.java Mon Sep 12 16:59:34 2011 -0700
@@ -478,7 +478,7 @@
fieldRefl = getReflector(fields, this);
} catch (InvalidClassException ex) {
// field mismatches impossible when matching local fields vs. self
- throw new InternalError();
+ throw new InternalError(ex);
}
if (deserializeEx == null) {
@@ -941,7 +941,7 @@
return cons.newInstance();
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
- throw new InternalError();
+ throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
@@ -969,7 +969,7 @@
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
- throw new InternalError();
+ throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
@@ -1000,7 +1000,7 @@
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
- throw new InternalError();
+ throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
@@ -1028,7 +1028,7 @@
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
- throw new InternalError();
+ throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
@@ -1053,11 +1053,11 @@
throw (ObjectStreamException) th;
} else {
throwMiscException(th);
- throw new InternalError(); // never reached
+ throw new InternalError(th); // never reached
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
- throw new InternalError();
+ throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
@@ -1082,11 +1082,11 @@
throw (ObjectStreamException) th;
} else {
throwMiscException(th);
- throw new InternalError(); // never reached
+ throw new InternalError(th); // never reached
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
- throw new InternalError();
+ throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
@@ -1774,7 +1774,7 @@
}
return hash;
} catch (IOException ex) {
- throw new InternalError();
+ throw new InternalError(ex);
} catch (NoSuchAlgorithmException ex) {
throw new SecurityException(ex.getMessage());
}
--- a/jdk/src/share/classes/java/lang/CharacterName.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/lang/CharacterName.java Mon Sep 12 16:59:34 2011 -0700
@@ -83,7 +83,7 @@
dis.readFully(strPool);
refStrPool = new SoftReference<>(strPool);
} catch (Exception x) {
- throw new InternalError(x.getMessage());
+ throw new InternalError(x.getMessage(), x);
} finally {
try {
if (dis != null)
--- a/jdk/src/share/classes/java/lang/Class.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/lang/Class.java Mon Sep 12 16:59:34 2011 -0700
@@ -974,8 +974,7 @@
descriptor = (String) enclosingInfo[2];
assert((name != null && descriptor != null) || name == descriptor);
} catch (ClassCastException cce) {
- throw (InternalError)
- new InternalError("Invalid type in enclosing method information").initCause(cce);
+ throw new InternalError("Invalid type in enclosing method information", cce);
}
}
@@ -1241,8 +1240,7 @@
try {
return getName().substring(enclosingClass.getName().length());
} catch (IndexOutOfBoundsException ex) {
- throw (InternalError)
- new InternalError("Malformed class name").initCause(ex);
+ throw new InternalError("Malformed class name", ex);
}
}
--- a/jdk/src/share/classes/java/lang/invoke/CallSite.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/CallSite.java Mon Sep 12 16:59:34 2011 -0700
@@ -27,7 +27,6 @@
import sun.invoke.empty.Empty;
import sun.misc.Unsafe;
-import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
@@ -244,8 +243,8 @@
try {
GET_TARGET = IMPL_LOOKUP.
findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
- } catch (ReflectiveOperationException ignore) {
- throw new InternalError();
+ } catch (ReflectiveOperationException e) {
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/lang/invoke/Invokers.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/Invokers.java Mon Sep 12 16:59:34 2011 -0700
@@ -88,7 +88,7 @@
try {
invoker = IMPL_LOOKUP.findVirtual(MethodHandle.class, name, targetType);
} catch (ReflectiveOperationException ex) {
- throw new InternalError("JVM cannot find invoker for "+targetType);
+ throw new InternalError("JVM cannot find invoker for "+targetType, ex);
}
assert(invokerType(targetType) == invoker.type());
assert(!invoker.isVarargsCollector());
--- a/jdk/src/share/classes/java/lang/invoke/MemberName.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MemberName.java Mon Sep 12 16:59:34 2011 -0700
@@ -382,7 +382,7 @@
try {
return (MemberName) super.clone();
} catch (CloneNotSupportedException ex) {
- throw new InternalError();
+ throw new InternalError(ex);
}
}
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java Mon Sep 12 16:59:34 2011 -0700
@@ -108,9 +108,7 @@
return new IllegalArgumentException(message(message, obj, obj2));
}
/*non-public*/ static Error uncaughtException(Exception ex) {
- Error err = new InternalError("uncaught exception");
- err.initCause(ex);
- return err;
+ throw new InternalError("uncaught exception", ex);
}
private static String message(String message, Object obj) {
if (obj != null) message = message + ": " + obj;
--- a/jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java Mon Sep 12 16:59:34 2011 -0700
@@ -461,7 +461,7 @@
// Trigger adapter creation.
genericInvoker = InvokeGeneric.generalInvokerOf(erasedType);
} catch (Exception ex) {
- Error err = new InternalError("Exception while resolving inexact invoke");
+ Error err = new InternalError("Exception while resolving inexact invoke", ex);
err.initCause(ex);
throw err;
}
--- a/jdk/src/share/classes/java/lang/reflect/Proxy.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/lang/reflect/Proxy.java Mon Sep 12 16:59:34 2011 -0700
@@ -610,7 +610,7 @@
IllegalAccessException |
InstantiationException |
InvocationTargetException e) {
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
--- a/jdk/src/share/classes/java/lang/reflect/TypeVariable.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/lang/reflect/TypeVariable.java Mon Sep 12 16:59:34 2011 -0700
@@ -48,7 +48,7 @@
*
* @since 1.5
*/
-public interface TypeVariable<D extends GenericDeclaration> extends Type {
+public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
/**
* Returns an array of {@code Type} objects representing the
* upper bound(s) of this type variable. Note that if no upper bound is
--- a/jdk/src/share/classes/java/math/BigDecimal.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/math/BigDecimal.java Mon Sep 12 16:59:34 2011 -0700
@@ -215,6 +215,7 @@
* @author Josh Bloch
* @author Mike Cowlishaw
* @author Joseph D. Darcy
+ * @author Sergey V. Kuksenko
*/
public class BigDecimal extends Number implements Comparable<BigDecimal> {
/**
@@ -224,7 +225,7 @@
* @serial
* @see #unscaledValue
*/
- private volatile BigInteger intVal;
+ private final BigInteger intVal;
/**
* The scale of this BigDecimal, as returned by {@link #scale}.
@@ -232,8 +233,9 @@
* @serial
* @see #scale
*/
- private int scale; // Note: this may have any value, so
- // calculations must be done in longs
+ private final int scale; // Note: this may have any value, so
+ // calculations must be done in longs
+
/**
* The number of decimal digits in this BigDecimal, or 0 if the
* number of digits are not known (lookaside information). If
@@ -256,19 +258,19 @@
*/
static final long INFLATED = Long.MIN_VALUE;
+ private static final BigInteger INFLATED_BIGINT = BigInteger.valueOf(INFLATED);
+
/**
* If the absolute value of the significand of this BigDecimal is
* less than or equal to {@code Long.MAX_VALUE}, the value can be
* compactly stored in this field and used in computations.
*/
- private transient long intCompact;
+ private final transient long intCompact;
// All 18-digit base ten strings fit into a long; not all 19-digit
// strings will
private static final int MAX_COMPACT_DIGITS = 18;
- private static final int MAX_BIGINT_BITS = 62;
-
/* Appease the serialization gods */
private static final long serialVersionUID = 6108874887143696463L;
@@ -282,17 +284,17 @@
// Cache of common small BigDecimal values.
private static final BigDecimal zeroThroughTen[] = {
- new BigDecimal(BigInteger.ZERO, 0, 0, 1),
- new BigDecimal(BigInteger.ONE, 1, 0, 1),
- new BigDecimal(BigInteger.valueOf(2), 2, 0, 1),
- new BigDecimal(BigInteger.valueOf(3), 3, 0, 1),
- new BigDecimal(BigInteger.valueOf(4), 4, 0, 1),
- new BigDecimal(BigInteger.valueOf(5), 5, 0, 1),
- new BigDecimal(BigInteger.valueOf(6), 6, 0, 1),
- new BigDecimal(BigInteger.valueOf(7), 7, 0, 1),
- new BigDecimal(BigInteger.valueOf(8), 8, 0, 1),
- new BigDecimal(BigInteger.valueOf(9), 9, 0, 1),
- new BigDecimal(BigInteger.TEN, 10, 0, 2),
+ new BigDecimal(BigInteger.ZERO, 0, 0, 1),
+ new BigDecimal(BigInteger.ONE, 1, 0, 1),
+ new BigDecimal(BigInteger.valueOf(2), 2, 0, 1),
+ new BigDecimal(BigInteger.valueOf(3), 3, 0, 1),
+ new BigDecimal(BigInteger.valueOf(4), 4, 0, 1),
+ new BigDecimal(BigInteger.valueOf(5), 5, 0, 1),
+ new BigDecimal(BigInteger.valueOf(6), 6, 0, 1),
+ new BigDecimal(BigInteger.valueOf(7), 7, 0, 1),
+ new BigDecimal(BigInteger.valueOf(8), 8, 0, 1),
+ new BigDecimal(BigInteger.valueOf(9), 9, 0, 1),
+ new BigDecimal(BigInteger.TEN, 10, 0, 2),
};
// Cache of zero scaled by 0 - 15
@@ -378,178 +380,7 @@
* @since 1.5
*/
public BigDecimal(char[] in, int offset, int len) {
- // protect against huge length.
- if (offset+len > in.length || offset < 0)
- throw new NumberFormatException();
- // This is the primary string to BigDecimal constructor; all
- // incoming strings end up here; it uses explicit (inline)
- // parsing for speed and generates at most one intermediate
- // (temporary) object (a char[] array) for non-compact case.
-
- // Use locals for all fields values until completion
- int prec = 0; // record precision value
- int scl = 0; // record scale value
- long rs = 0; // the compact value in long
- BigInteger rb = null; // the inflated value in BigInteger
-
- // use array bounds checking to handle too-long, len == 0,
- // bad offset, etc.
- try {
- // handle the sign
- boolean isneg = false; // assume positive
- if (in[offset] == '-') {
- isneg = true; // leading minus means negative
- offset++;
- len--;
- } else if (in[offset] == '+') { // leading + allowed
- offset++;
- len--;
- }
-
- // should now be at numeric part of the significand
- boolean dot = false; // true when there is a '.'
- int cfirst = offset; // record start of integer
- long exp = 0; // exponent
- char c; // current character
-
- boolean isCompact = (len <= MAX_COMPACT_DIGITS);
- // integer significand array & idx is the index to it. The array
- // is ONLY used when we can't use a compact representation.
- char coeff[] = isCompact ? null : new char[len];
- int idx = 0;
-
- for (; len > 0; offset++, len--) {
- c = in[offset];
- // have digit
- if ((c >= '0' && c <= '9') || Character.isDigit(c)) {
- // First compact case, we need not to preserve the character
- // and we can just compute the value in place.
- if (isCompact) {
- int digit = Character.digit(c, 10);
- if (digit == 0) {
- if (prec == 0)
- prec = 1;
- else if (rs != 0) {
- rs *= 10;
- ++prec;
- } // else digit is a redundant leading zero
- } else {
- if (prec != 1 || rs != 0)
- ++prec; // prec unchanged if preceded by 0s
- rs = rs * 10 + digit;
- }
- } else { // the unscaled value is likely a BigInteger object.
- if (c == '0' || Character.digit(c, 10) == 0) {
- if (prec == 0) {
- coeff[idx] = c;
- prec = 1;
- } else if (idx != 0) {
- coeff[idx++] = c;
- ++prec;
- } // else c must be a redundant leading zero
- } else {
- if (prec != 1 || idx != 0)
- ++prec; // prec unchanged if preceded by 0s
- coeff[idx++] = c;
- }
- }
- if (dot)
- ++scl;
- continue;
- }
- // have dot
- if (c == '.') {
- // have dot
- if (dot) // two dots
- throw new NumberFormatException();
- dot = true;
- continue;
- }
- // exponent expected
- if ((c != 'e') && (c != 'E'))
- throw new NumberFormatException();
- offset++;
- c = in[offset];
- len--;
- boolean negexp = (c == '-');
- // optional sign
- if (negexp || c == '+') {
- offset++;
- c = in[offset];
- len--;
- }
- if (len <= 0) // no exponent digits
- throw new NumberFormatException();
- // skip leading zeros in the exponent
- while (len > 10 && Character.digit(c, 10) == 0) {
- offset++;
- c = in[offset];
- len--;
- }
- if (len > 10) // too many nonzero exponent digits
- throw new NumberFormatException();
- // c now holds first digit of exponent
- for (;; len--) {
- int v;
- if (c >= '0' && c <= '9') {
- v = c - '0';
- } else {
- v = Character.digit(c, 10);
- if (v < 0) // not a digit
- throw new NumberFormatException();
- }
- exp = exp * 10 + v;
- if (len == 1)
- break; // that was final character
- offset++;
- c = in[offset];
- }
- if (negexp) // apply sign
- exp = -exp;
- // Next test is required for backwards compatibility
- if ((int)exp != exp) // overflow
- throw new NumberFormatException();
- break; // [saves a test]
- }
- // here when no characters left
- if (prec == 0) // no digits found
- throw new NumberFormatException();
-
- // Adjust scale if exp is not zero.
- if (exp != 0) { // had significant exponent
- // Can't call checkScale which relies on proper fields value
- long adjustedScale = scl - exp;
- if (adjustedScale > Integer.MAX_VALUE ||
- adjustedScale < Integer.MIN_VALUE)
- throw new NumberFormatException("Scale out of range.");
- scl = (int)adjustedScale;
- }
-
- // Remove leading zeros from precision (digits count)
- if (isCompact) {
- rs = isneg ? -rs : rs;
- } else {
- char quick[];
- if (!isneg) {
- quick = (coeff.length != prec) ?
- Arrays.copyOf(coeff, prec) : coeff;
- } else {
- quick = new char[prec + 1];
- quick[0] = '-';
- System.arraycopy(coeff, 0, quick, 1, prec);
- }
- rb = new BigInteger(quick);
- rs = compactValFor(rb);
- }
- } catch (ArrayIndexOutOfBoundsException e) {
- throw new NumberFormatException();
- } catch (NegativeArraySizeException e) {
- throw new NumberFormatException();
- }
- this.scale = scl;
- this.precision = prec;
- this.intCompact = rs;
- this.intVal = (rs != INFLATED) ? null : rb;
+ this(in,offset,len,MathContext.UNLIMITED);
}
/**
@@ -576,9 +407,254 @@
* @since 1.5
*/
public BigDecimal(char[] in, int offset, int len, MathContext mc) {
- this(in, offset, len);
- if (mc.precision > 0)
- roundThis(mc);
+ // protect against huge length.
+ if (offset + len > in.length || offset < 0)
+ throw new NumberFormatException("Bad offset or len arguments for char[] input.");
+ // This is the primary string to BigDecimal constructor; all
+ // incoming strings end up here; it uses explicit (inline)
+ // parsing for speed and generates at most one intermediate
+ // (temporary) object (a char[] array) for non-compact case.
+
+ // Use locals for all fields values until completion
+ int prec = 0; // record precision value
+ int scl = 0; // record scale value
+ long rs = 0; // the compact value in long
+ BigInteger rb = null; // the inflated value in BigInteger
+ // use array bounds checking to handle too-long, len == 0,
+ // bad offset, etc.
+ try {
+ // handle the sign
+ boolean isneg = false; // assume positive
+ if (in[offset] == '-') {
+ isneg = true; // leading minus means negative
+ offset++;
+ len--;
+ } else if (in[offset] == '+') { // leading + allowed
+ offset++;
+ len--;
+ }
+
+ // should now be at numeric part of the significand
+ boolean dot = false; // true when there is a '.'
+ long exp = 0; // exponent
+ char c; // current character
+ boolean isCompact = (len <= MAX_COMPACT_DIGITS);
+ // integer significand array & idx is the index to it. The array
+ // is ONLY used when we can't use a compact representation.
+ int idx = 0;
+ if (isCompact) {
+ // First compact case, we need not to preserve the character
+ // and we can just compute the value in place.
+ for (; len > 0; offset++, len--) {
+ c = in[offset];
+ if ((c == '0')) { // have zero
+ if (prec == 0)
+ prec = 1;
+ else if (rs != 0) {
+ rs *= 10;
+ ++prec;
+ } // else digit is a redundant leading zero
+ if (dot)
+ ++scl;
+ } else if ((c >= '1' && c <= '9')) { // have digit
+ int digit = c - '0';
+ if (prec != 1 || rs != 0)
+ ++prec; // prec unchanged if preceded by 0s
+ rs = rs * 10 + digit;
+ if (dot)
+ ++scl;
+ } else if (c == '.') { // have dot
+ // have dot
+ if (dot) // two dots
+ throw new NumberFormatException();
+ dot = true;
+ } else if (Character.isDigit(c)) { // slow path
+ int digit = Character.digit(c, 10);
+ if (digit == 0) {
+ if (prec == 0)
+ prec = 1;
+ else if (rs != 0) {
+ rs *= 10;
+ ++prec;
+ } // else digit is a redundant leading zero
+ } else {
+ if (prec != 1 || rs != 0)
+ ++prec; // prec unchanged if preceded by 0s
+ rs = rs * 10 + digit;
+ }
+ if (dot)
+ ++scl;
+ } else if ((c == 'e') || (c == 'E')) {
+ exp = parseExp(in, offset, len);
+ // Next test is required for backwards compatibility
+ if ((int) exp != exp) // overflow
+ throw new NumberFormatException();
+ break; // [saves a test]
+ } else {
+ throw new NumberFormatException();
+ }
+ }
+ if (prec == 0) // no digits found
+ throw new NumberFormatException();
+ // Adjust scale if exp is not zero.
+ if (exp != 0) { // had significant exponent
+ scl = adjustScale(scl, exp);
+ }
+ rs = isneg ? -rs : rs;
+ int mcp = mc.precision;
+ int drop = prec - mcp; // prec has range [1, MAX_INT], mcp has range [0, MAX_INT];
+ // therefore, this subtract cannot overflow
+ if (mcp > 0 && drop > 0) { // do rounding
+ while (drop > 0) {
+ scl = checkScaleNonZero((long) scl - drop);
+ rs = divideAndRound(rs, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
+ prec = longDigitLength(rs);
+ drop = prec - mcp;
+ }
+ }
+ } else {
+ char coeff[] = new char[len];
+ for (; len > 0; offset++, len--) {
+ c = in[offset];
+ // have digit
+ if ((c >= '0' && c <= '9') || Character.isDigit(c)) {
+ // First compact case, we need not to preserve the character
+ // and we can just compute the value in place.
+ if (c == '0' || Character.digit(c, 10) == 0) {
+ if (prec == 0) {
+ coeff[idx] = c;
+ prec = 1;
+ } else if (idx != 0) {
+ coeff[idx++] = c;
+ ++prec;
+ } // else c must be a redundant leading zero
+ } else {
+ if (prec != 1 || idx != 0)
+ ++prec; // prec unchanged if preceded by 0s
+ coeff[idx++] = c;
+ }
+ if (dot)
+ ++scl;
+ continue;
+ }
+ // have dot
+ if (c == '.') {
+ // have dot
+ if (dot) // two dots
+ throw new NumberFormatException();
+ dot = true;
+ continue;
+ }
+ // exponent expected
+ if ((c != 'e') && (c != 'E'))
+ throw new NumberFormatException();
+ exp = parseExp(in, offset, len);
+ // Next test is required for backwards compatibility
+ if ((int) exp != exp) // overflow
+ throw new NumberFormatException();
+ break; // [saves a test]
+ }
+ // here when no characters left
+ if (prec == 0) // no digits found
+ throw new NumberFormatException();
+ // Adjust scale if exp is not zero.
+ if (exp != 0) { // had significant exponent
+ scl = adjustScale(scl, exp);
+ }
+ // Remove leading zeros from precision (digits count)
+ rb = new BigInteger(coeff, isneg ? -1 : 1, prec);
+ rs = compactValFor(rb);
+ int mcp = mc.precision;
+ if (mcp > 0 && (prec > mcp)) {
+ if (rs == INFLATED) {
+ int drop = prec - mcp;
+ while (drop > 0) {
+ scl = checkScaleNonZero((long) scl - drop);
+ rb = divideAndRoundByTenPow(rb, drop, mc.roundingMode.oldMode);
+ rs = compactValFor(rb);
+ if (rs != INFLATED) {
+ prec = longDigitLength(rs);
+ break;
+ }
+ prec = bigDigitLength(rb);
+ drop = prec - mcp;
+ }
+ }
+ if (rs != INFLATED) {
+ int drop = prec - mcp;
+ while (drop > 0) {
+ scl = checkScaleNonZero((long) scl - drop);
+ rs = divideAndRound(rs, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
+ prec = longDigitLength(rs);
+ drop = prec - mcp;
+ }
+ rb = null;
+ }
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new NumberFormatException();
+ } catch (NegativeArraySizeException e) {
+ throw new NumberFormatException();
+ }
+ this.scale = scl;
+ this.precision = prec;
+ this.intCompact = rs;
+ this.intVal = rb;
+ }
+
+ private int adjustScale(int scl, long exp) {
+ long adjustedScale = scl - exp;
+ if (adjustedScale > Integer.MAX_VALUE || adjustedScale < Integer.MIN_VALUE)
+ throw new NumberFormatException("Scale out of range.");
+ scl = (int) adjustedScale;
+ return scl;
+ }
+
+ /*
+ * parse exponent
+ */
+ private static long parseExp(char[] in, int offset, int len){
+ long exp = 0;
+ offset++;
+ char c = in[offset];
+ len--;
+ boolean negexp = (c == '-');
+ // optional sign
+ if (negexp || c == '+') {
+ offset++;
+ c = in[offset];
+ len--;
+ }
+ if (len <= 0) // no exponent digits
+ throw new NumberFormatException();
+ // skip leading zeros in the exponent
+ while (len > 10 && (c=='0' || (Character.digit(c, 10) == 0))) {
+ offset++;
+ c = in[offset];
+ len--;
+ }
+ if (len > 10) // too many nonzero exponent digits
+ throw new NumberFormatException();
+ // c now holds first digit of exponent
+ for (;; len--) {
+ int v;
+ if (c >= '0' && c <= '9') {
+ v = c - '0';
+ } else {
+ v = Character.digit(c, 10);
+ if (v < 0) // not a digit
+ throw new NumberFormatException();
+ }
+ exp = exp * 10 + v;
+ if (len == 1)
+ break; // that was final character
+ offset++;
+ c = in[offset];
+ }
+ if (negexp) // apply sign
+ exp = -exp;
+ return exp;
}
/**
@@ -754,9 +830,7 @@
* @since 1.5
*/
public BigDecimal(String val, MathContext mc) {
- this(val.toCharArray(), 0, val.length());
- if (mc.precision > 0)
- roundThis(mc);
+ this(val.toCharArray(), 0, val.length(), mc);
}
/**
@@ -804,49 +878,7 @@
* @throws NumberFormatException if {@code val} is infinite or NaN.
*/
public BigDecimal(double val) {
- if (Double.isInfinite(val) || Double.isNaN(val))
- throw new NumberFormatException("Infinite or NaN");
-
- // Translate the double into sign, exponent and significand, according
- // to the formulae in JLS, Section 20.10.22.
- long valBits = Double.doubleToLongBits(val);
- int sign = ((valBits >> 63)==0 ? 1 : -1);
- int exponent = (int) ((valBits >> 52) & 0x7ffL);
- long significand = (exponent==0 ? (valBits & ((1L<<52) - 1)) << 1
- : (valBits & ((1L<<52) - 1)) | (1L<<52));
- exponent -= 1075;
- // At this point, val == sign * significand * 2**exponent.
-
- /*
- * Special case zero to supress nonterminating normalization
- * and bogus scale calculation.
- */
- if (significand == 0) {
- intVal = BigInteger.ZERO;
- intCompact = 0;
- precision = 1;
- return;
- }
-
- // Normalize
- while((significand & 1) == 0) { // i.e., significand is even
- significand >>= 1;
- exponent++;
- }
-
- // Calculate intVal and scale
- long s = sign * significand;
- BigInteger b;
- if (exponent < 0) {
- b = BigInteger.valueOf(5).pow(-exponent).multiply(s);
- scale = -exponent;
- } else if (exponent > 0) {
- b = BigInteger.valueOf(2).pow(exponent).multiply(s);
- } else {
- b = BigInteger.valueOf(s);
- }
- intCompact = compactValFor(b);
- intVal = (intCompact != INFLATED) ? null : b;
+ this(val,MathContext.UNLIMITED);
}
/**
@@ -868,9 +900,85 @@
* @since 1.5
*/
public BigDecimal(double val, MathContext mc) {
- this(val);
- if (mc.precision > 0)
- roundThis(mc);
+ if (Double.isInfinite(val) || Double.isNaN(val))
+ throw new NumberFormatException("Infinite or NaN");
+ // Translate the double into sign, exponent and significand, according
+ // to the formulae in JLS, Section 20.10.22.
+ long valBits = Double.doubleToLongBits(val);
+ int sign = ((valBits >> 63) == 0 ? 1 : -1);
+ int exponent = (int) ((valBits >> 52) & 0x7ffL);
+ long significand = (exponent == 0
+ ? (valBits & ((1L << 52) - 1)) << 1
+ : (valBits & ((1L << 52) - 1)) | (1L << 52));
+ exponent -= 1075;
+ // At this point, val == sign * significand * 2**exponent.
+
+ /*
+ * Special case zero to supress nonterminating normalization and bogus
+ * scale calculation.
+ */
+ if (significand == 0) {
+ this.intVal = BigInteger.ZERO;
+ this.scale = 0;
+ this.intCompact = 0;
+ this.precision = 1;
+ return;
+ }
+ // Normalize
+ while ((significand & 1) == 0) { // i.e., significand is even
+ significand >>= 1;
+ exponent++;
+ }
+ int scale = 0;
+ // Calculate intVal and scale
+ BigInteger intVal;
+ long compactVal = sign * significand;
+ if (exponent == 0) {
+ intVal = (compactVal == INFLATED) ? INFLATED_BIGINT : null;
+ } else {
+ if (exponent < 0) {
+ intVal = BigInteger.valueOf(5).pow(-exponent).multiply(compactVal);
+ scale = -exponent;
+ } else { // (exponent > 0)
+ intVal = BigInteger.valueOf(2).pow(exponent).multiply(compactVal);
+ }
+ compactVal = compactValFor(intVal);
+ }
+ int prec = 0;
+ int mcp = mc.precision;
+ if (mcp > 0) { // do rounding
+ int mode = mc.roundingMode.oldMode;
+ int drop;
+ if (compactVal == INFLATED) {
+ prec = bigDigitLength(intVal);
+ drop = prec - mcp;
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ intVal = divideAndRoundByTenPow(intVal, drop, mode);
+ compactVal = compactValFor(intVal);
+ if (compactVal != INFLATED) {
+ break;
+ }
+ prec = bigDigitLength(intVal);
+ drop = prec - mcp;
+ }
+ }
+ if (compactVal != INFLATED) {
+ prec = longDigitLength(compactVal);
+ drop = prec - mcp;
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
+ prec = longDigitLength(compactVal);
+ drop = prec - mcp;
+ }
+ intVal = null;
+ }
+ }
+ this.intVal = intVal;
+ this.intCompact = compactVal;
+ this.scale = scale;
+ this.precision = prec;
}
/**
@@ -881,8 +989,9 @@
* {@code BigDecimal}.
*/
public BigDecimal(BigInteger val) {
+ scale = 0;
+ intVal = val;
intCompact = compactValFor(val);
- intVal = (intCompact != INFLATED) ? null : val;
}
/**
@@ -898,9 +1007,7 @@
* @since 1.5
*/
public BigDecimal(BigInteger val, MathContext mc) {
- this(val);
- if (mc.precision > 0)
- roundThis(mc);
+ this(val,0,mc);
}
/**
@@ -914,7 +1021,8 @@
*/
public BigDecimal(BigInteger unscaledVal, int scale) {
// Negative scales are now allowed
- this(unscaledVal);
+ this.intVal = unscaledVal;
+ this.intCompact = compactValFor(unscaledVal);
this.scale = scale;
}
@@ -934,10 +1042,41 @@
* @since 1.5
*/
public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) {
- this(unscaledVal);
+ long compactVal = compactValFor(unscaledVal);
+ int mcp = mc.precision;
+ int prec = 0;
+ if (mcp > 0) { // do rounding
+ int mode = mc.roundingMode.oldMode;
+ if (compactVal == INFLATED) {
+ prec = bigDigitLength(unscaledVal);
+ int drop = prec - mcp;
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ unscaledVal = divideAndRoundByTenPow(unscaledVal, drop, mode);
+ compactVal = compactValFor(unscaledVal);
+ if (compactVal != INFLATED) {
+ break;
+ }
+ prec = bigDigitLength(unscaledVal);
+ drop = prec - mcp;
+ }
+ }
+ if (compactVal != INFLATED) {
+ prec = longDigitLength(compactVal);
+ int drop = prec - mcp; // drop can't be more than 18
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mode);
+ prec = longDigitLength(compactVal);
+ drop = prec - mcp;
+ }
+ unscaledVal = null;
+ }
+ }
+ this.intVal = unscaledVal;
+ this.intCompact = compactVal;
this.scale = scale;
- if (mc.precision > 0)
- roundThis(mc);
+ this.precision = prec;
}
/**
@@ -949,7 +1088,9 @@
* @since 1.5
*/
public BigDecimal(int val) {
- intCompact = val;
+ this.intCompact = val;
+ this.scale = 0;
+ this.intVal = null;
}
/**
@@ -964,9 +1105,24 @@
* @since 1.5
*/
public BigDecimal(int val, MathContext mc) {
- intCompact = val;
- if (mc.precision > 0)
- roundThis(mc);
+ int mcp = mc.precision;
+ long compactVal = val;
+ int scale = 0;
+ int prec = 0;
+ if (mcp > 0) { // do rounding
+ prec = longDigitLength(compactVal);
+ int drop = prec - mcp; // drop can't be more than 18
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
+ prec = longDigitLength(compactVal);
+ drop = prec - mcp;
+ }
+ }
+ this.intVal = null;
+ this.intCompact = compactVal;
+ this.scale = scale;
+ this.precision = prec;
}
/**
@@ -978,7 +1134,8 @@
*/
public BigDecimal(long val) {
this.intCompact = val;
- this.intVal = (val == INFLATED) ? BigInteger.valueOf(val) : null;
+ this.intVal = (val == INFLATED) ? INFLATED_BIGINT : null;
+ this.scale = 0;
}
/**
@@ -993,9 +1150,42 @@
* @since 1.5
*/
public BigDecimal(long val, MathContext mc) {
- this(val);
- if (mc.precision > 0)
- roundThis(mc);
+ int mcp = mc.precision;
+ int mode = mc.roundingMode.oldMode;
+ int prec = 0;
+ int scale = 0;
+ BigInteger intVal = (val == INFLATED) ? INFLATED_BIGINT : null;
+ if (mcp > 0) { // do rounding
+ if (val == INFLATED) {
+ prec = 19;
+ int drop = prec - mcp;
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ intVal = divideAndRoundByTenPow(intVal, drop, mode);
+ val = compactValFor(intVal);
+ if (val != INFLATED) {
+ break;
+ }
+ prec = bigDigitLength(intVal);
+ drop = prec - mcp;
+ }
+ }
+ if (val != INFLATED) {
+ prec = longDigitLength(val);
+ int drop = prec - mcp;
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ val = divideAndRound(val, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
+ prec = longDigitLength(val);
+ drop = prec - mcp;
+ }
+ intVal = null;
+ }
+ }
+ this.intVal = intVal;
+ this.intCompact = val;
+ this.scale = scale;
+ this.precision = prec;
}
// Static Factory Methods
@@ -1016,13 +1206,10 @@
if (scale == 0)
return valueOf(unscaledVal);
else if (unscaledVal == 0) {
- if (scale > 0 && scale < ZERO_SCALED_BY.length)
- return ZERO_SCALED_BY[scale];
- else
- return new BigDecimal(BigInteger.ZERO, 0, scale, 1);
+ return zeroValueOf(scale);
}
return new BigDecimal(unscaledVal == INFLATED ?
- BigInteger.valueOf(unscaledVal) : null,
+ INFLATED_BIGINT : null,
unscaledVal, scale, 0);
}
@@ -1041,7 +1228,34 @@
return zeroThroughTen[(int)val];
else if (val != INFLATED)
return new BigDecimal(null, val, 0, 0);
- return new BigDecimal(BigInteger.valueOf(val), val, 0, 0);
+ return new BigDecimal(INFLATED_BIGINT, val, 0, 0);
+ }
+
+ static BigDecimal valueOf(long unscaledVal, int scale, int prec) {
+ if (scale == 0 && unscaledVal >= 0 && unscaledVal < zeroThroughTen.length) {
+ return zeroThroughTen[(int) unscaledVal];
+ } else if (unscaledVal == 0) {
+ return zeroValueOf(scale);
+ }
+ return new BigDecimal(unscaledVal == INFLATED ? INFLATED_BIGINT : null,
+ unscaledVal, scale, prec);
+ }
+
+ static BigDecimal valueOf(BigInteger intVal, int scale, int prec) {
+ long val = compactValFor(intVal);
+ if (val == 0) {
+ return zeroValueOf(scale);
+ } else if (scale == 0 && val >= 0 && val < zeroThroughTen.length) {
+ return zeroThroughTen[(int) val];
+ }
+ return new BigDecimal(intVal, val, scale, prec);
+ }
+
+ static BigDecimal zeroValueOf(int scale) {
+ if (scale >= 0 && scale < ZERO_SCALED_BY.length)
+ return ZERO_SCALED_BY[scale];
+ else
+ return new BigDecimal(BigInteger.ZERO, 0, scale, 1);
}
/**
@@ -1079,42 +1293,19 @@
* @return {@code this + augend}
*/
public BigDecimal add(BigDecimal augend) {
- long xs = this.intCompact;
- long ys = augend.intCompact;
- BigInteger fst = (xs != INFLATED) ? null : this.intVal;
- BigInteger snd = (ys != INFLATED) ? null : augend.intVal;
- int rscale = this.scale;
-
- long sdiff = (long)rscale - augend.scale;
- if (sdiff != 0) {
- if (sdiff < 0) {
- int raise = checkScale(-sdiff);
- rscale = augend.scale;
- if (xs == INFLATED ||
- (xs = longMultiplyPowerTen(xs, raise)) == INFLATED)
- fst = bigMultiplyPowerTen(raise);
+ if (this.intCompact != INFLATED) {
+ if ((augend.intCompact != INFLATED)) {
+ return add(this.intCompact, this.scale, augend.intCompact, augend.scale);
} else {
- int raise = augend.checkScale(sdiff);
- if (ys == INFLATED ||
- (ys = longMultiplyPowerTen(ys, raise)) == INFLATED)
- snd = augend.bigMultiplyPowerTen(raise);
+ return add(this.intCompact, this.scale, augend.intVal, augend.scale);
+ }
+ } else {
+ if ((augend.intCompact != INFLATED)) {
+ return add(augend.intCompact, augend.scale, this.intVal, this.scale);
+ } else {
+ return add(this.intVal, this.scale, augend.intVal, augend.scale);
}
}
- if (xs != INFLATED && ys != INFLATED) {
- long sum = xs + ys;
- // See "Hacker's Delight" section 2-12 for explanation of
- // the overflow test.
- if ( (((sum ^ xs) & (sum ^ ys))) >= 0L) // not overflowed
- return BigDecimal.valueOf(sum, rscale);
- }
- if (fst == null)
- fst = BigInteger.valueOf(xs);
- if (snd == null)
- snd = BigInteger.valueOf(ys);
- BigInteger sum = fst.add(snd);
- return (fst.signum == snd.signum) ?
- new BigDecimal(sum, INFLATED, rscale, 0) :
- new BigDecimal(sum, rscale);
}
/**
@@ -1136,10 +1327,6 @@
return add(augend);
BigDecimal lhs = this;
- // Could optimize if values are compact
- this.inflate();
- augend.inflate();
-
// If either number is zero then the other number, rounded and
// scaled if necessary, is used as the result.
{
@@ -1150,20 +1337,14 @@
int preferredScale = Math.max(lhs.scale(), augend.scale());
BigDecimal result;
- // Could use a factory for zero instead of a new object
if (lhsIsZero && augendIsZero)
- return new BigDecimal(BigInteger.ZERO, 0, preferredScale, 0);
-
+ return zeroValueOf(preferredScale);
result = lhsIsZero ? doRound(augend, mc) : doRound(lhs, mc);
if (result.scale() == preferredScale)
return result;
else if (result.scale() > preferredScale) {
- BigDecimal scaledResult =
- new BigDecimal(result.intVal, result.intCompact,
- result.scale, 0);
- scaledResult.stripZerosToMatchScale(preferredScale);
- return scaledResult;
+ return stripZerosToMatchScale(result.intVal, result.intCompact, result.scale, preferredScale);
} else { // result.scale < preferredScale
int precisionDiff = mc.precision - result.precision();
int scaleDiff = preferredScale - result.scale();
@@ -1176,17 +1357,14 @@
}
}
- long padding = (long)lhs.scale - augend.scale;
- if (padding != 0) { // scales differ; alignment needed
+ long padding = (long) lhs.scale - augend.scale;
+ if (padding != 0) { // scales differ; alignment needed
BigDecimal arg[] = preAlign(lhs, augend, padding, mc);
matchScale(arg);
- lhs = arg[0];
+ lhs = arg[0];
augend = arg[1];
}
-
- BigDecimal d = new BigDecimal(lhs.inflate().add(augend.inflate()),
- lhs.scale);
- return doRound(d, mc);
+ return doRound(lhs.inflated().add(augend.inflated()), lhs.scale, mc);
}
/**
@@ -1211,27 +1389,26 @@
* that the number of digits of the smaller operand could be
* reduced even though the significands partially overlapped.
*/
- private BigDecimal[] preAlign(BigDecimal lhs, BigDecimal augend,
- long padding, MathContext mc) {
+ private BigDecimal[] preAlign(BigDecimal lhs, BigDecimal augend, long padding, MathContext mc) {
assert padding != 0;
BigDecimal big;
BigDecimal small;
- if (padding < 0) { // lhs is big; augend is small
- big = lhs;
+ if (padding < 0) { // lhs is big; augend is small
+ big = lhs;
small = augend;
- } else { // lhs is small; augend is big
- big = augend;
+ } else { // lhs is small; augend is big
+ big = augend;
small = lhs;
}
/*
- * This is the estimated scale of an ulp of the result; it
- * assumes that the result doesn't have a carry-out on a true
- * add (e.g. 999 + 1 => 1000) or any subtractive cancellation
- * on borrowing (e.g. 100 - 1.2 => 98.8)
+ * This is the estimated scale of an ulp of the result; it assumes that
+ * the result doesn't have a carry-out on a true add (e.g. 999 + 1 =>
+ * 1000) or any subtractive cancellation on borrowing (e.g. 100 - 1.2 =>
+ * 98.8)
*/
- long estResultUlpScale = (long)big.scale - big.precision() + mc.precision;
+ long estResultUlpScale = (long) big.scale - big.precision() + mc.precision;
/*
* The low-order digit position of big is big.scale(). This
@@ -1242,11 +1419,10 @@
* disjoint *and* the digit positions of small should not be
* directly visible in the result.
*/
- long smallHighDigitPos = (long)small.scale - small.precision() + 1;
- if (smallHighDigitPos > big.scale + 2 && // big and small disjoint
+ long smallHighDigitPos = (long) small.scale - small.precision() + 1;
+ if (smallHighDigitPos > big.scale + 2 && // big and small disjoint
smallHighDigitPos > estResultUlpScale + 2) { // small digits not visible
- small = BigDecimal.valueOf(small.signum(),
- this.checkScale(Math.max(big.scale, estResultUlpScale) + 3));
+ small = BigDecimal.valueOf(small.signum(), this.checkScale(Math.max(big.scale, estResultUlpScale) + 3));
}
// Since addition is symmetric, preserving input order in
@@ -1264,7 +1440,22 @@
* @return {@code this - subtrahend}
*/
public BigDecimal subtract(BigDecimal subtrahend) {
- return add(subtrahend.negate());
+ if (this.intCompact != INFLATED) {
+ if ((subtrahend.intCompact != INFLATED)) {
+ return add(this.intCompact, this.scale, -subtrahend.intCompact, subtrahend.scale);
+ } else {
+ return add(this.intCompact, this.scale, subtrahend.intVal.negate(), subtrahend.scale);
+ }
+ } else {
+ if ((subtrahend.intCompact != INFLATED)) {
+ // Pair of subtrahend values given before pair of
+ // values from this BigDecimal to avoid need for
+ // method overloading on the specialized add method
+ return add(-subtrahend.intCompact, subtrahend.scale, this.intVal, this.scale);
+ } else {
+ return add(this.intVal, this.scale, subtrahend.intVal.negate(), subtrahend.scale);
+ }
+ }
}
/**
@@ -1282,11 +1473,10 @@
* @since 1.5
*/
public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) {
- BigDecimal nsubtrahend = subtrahend.negate();
if (mc.precision == 0)
- return add(nsubtrahend);
+ return subtract(subtrahend);
// share the special rounding code in add()
- return add(nsubtrahend, mc);
+ return add(subtrahend.negate(), mc);
}
/**
@@ -1298,37 +1488,20 @@
* @return {@code this * multiplicand}
*/
public BigDecimal multiply(BigDecimal multiplicand) {
- long x = this.intCompact;
- long y = multiplicand.intCompact;
- int productScale = checkScale((long)scale + multiplicand.scale);
-
- // Might be able to do a more clever check incorporating the
- // inflated check into the overflow computation.
- if (x != INFLATED && y != INFLATED) {
- /*
- * If the product is not an overflowed value, continue
- * to use the compact representation. if either of x or y
- * is INFLATED, the product should also be regarded as
- * an overflow. Before using the overflow test suggested in
- * "Hacker's Delight" section 2-12, we perform quick checks
- * using the precision information to see whether the overflow
- * would occur since division is expensive on most CPUs.
- */
- long product = x * y;
- long prec = this.precision() + multiplicand.precision();
- if (prec < 19 || (prec < 21 && (y == 0 || product / y == x)))
- return BigDecimal.valueOf(product, productScale);
- return new BigDecimal(BigInteger.valueOf(x).multiply(y), INFLATED,
- productScale, 0);
+ int productScale = checkScale((long) scale + multiplicand.scale);
+ if (this.intCompact != INFLATED) {
+ if ((multiplicand.intCompact != INFLATED)) {
+ return multiply(this.intCompact, multiplicand.intCompact, productScale);
+ } else {
+ return multiply(this.intCompact, multiplicand.intVal, productScale);
+ }
+ } else {
+ if ((multiplicand.intCompact != INFLATED)) {
+ return multiply(multiplicand.intCompact, this.intVal, productScale);
+ } else {
+ return multiply(this.intVal, multiplicand.intVal, productScale);
+ }
}
- BigInteger rb;
- if (x == INFLATED && y == INFLATED)
- rb = this.intVal.multiply(multiplicand.intVal);
- else if (x != INFLATED)
- rb = multiplicand.intVal.multiply(x);
- else
- rb = this.intVal.multiply(y);
- return new BigDecimal(rb, INFLATED, productScale, 0);
}
/**
@@ -1345,7 +1518,20 @@
public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) {
if (mc.precision == 0)
return multiply(multiplicand);
- return doRound(this.multiply(multiplicand), mc);
+ int productScale = checkScale((long) scale + multiplicand.scale);
+ if (this.intCompact != INFLATED) {
+ if ((multiplicand.intCompact != INFLATED)) {
+ return multiplyAndRound(this.intCompact, multiplicand.intCompact, productScale, mc);
+ } else {
+ return multiplyAndRound(this.intCompact, multiplicand.intVal, productScale, mc);
+ }
+ } else {
+ if ((multiplicand.intCompact != INFLATED)) {
+ return multiplyAndRound(multiplicand.intCompact, this.intVal, productScale, mc);
+ } else {
+ return multiplyAndRound(this.intVal, multiplicand.intVal, productScale, mc);
+ }
+ }
}
/**
@@ -1377,120 +1563,21 @@
* @see #ROUND_UNNECESSARY
*/
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
- /*
- * IMPLEMENTATION NOTE: This method *must* return a new object
- * since divideAndRound uses divide to generate a value whose
- * scale is then modified.
- */
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
throw new IllegalArgumentException("Invalid rounding mode");
- /*
- * Rescale dividend or divisor (whichever can be "upscaled" to
- * produce correctly scaled quotient).
- * Take care to detect out-of-range scales
- */
- BigDecimal dividend = this;
- if (checkScale((long)scale + divisor.scale) > this.scale)
- dividend = this.setScale(scale + divisor.scale, ROUND_UNNECESSARY);
- else
- divisor = divisor.setScale(checkScale((long)this.scale - scale),
- ROUND_UNNECESSARY);
- return divideAndRound(dividend.intCompact, dividend.intVal,
- divisor.intCompact, divisor.intVal,
- scale, roundingMode, scale);
- }
-
- /**
- * Internally used for division operation. The dividend and divisor are
- * passed both in {@code long} format and {@code BigInteger} format. The
- * returned {@code BigDecimal} object is the quotient whose scale is set to
- * the passed in scale. If the remainder is not zero, it will be rounded
- * based on the passed in roundingMode. Also, if the remainder is zero and
- * the last parameter, i.e. preferredScale is NOT equal to scale, the
- * trailing zeros of the result is stripped to match the preferredScale.
- */
- private static BigDecimal divideAndRound(long ldividend, BigInteger bdividend,
- long ldivisor, BigInteger bdivisor,
- int scale, int roundingMode,
- int preferredScale) {
- boolean isRemainderZero; // record remainder is zero or not
- int qsign; // quotient sign
- long q = 0, r = 0; // store quotient & remainder in long
- MutableBigInteger mq = null; // store quotient
- MutableBigInteger mr = null; // store remainder
- MutableBigInteger mdivisor = null;
- boolean isLongDivision = (ldividend != INFLATED && ldivisor != INFLATED);
- if (isLongDivision) {
- q = ldividend / ldivisor;
- if (roundingMode == ROUND_DOWN && scale == preferredScale)
- return new BigDecimal(null, q, scale, 0);
- r = ldividend % ldivisor;
- isRemainderZero = (r == 0);
- qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
+ if (this.intCompact != INFLATED) {
+ if ((divisor.intCompact != INFLATED)) {
+ return divide(this.intCompact, this.scale, divisor.intCompact, divisor.scale, scale, roundingMode);
+ } else {
+ return divide(this.intCompact, this.scale, divisor.intVal, divisor.scale, scale, roundingMode);
+ }
} else {
- if (bdividend == null)
- bdividend = BigInteger.valueOf(ldividend);
- // Descend into mutables for faster remainder checks
- MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
- mq = new MutableBigInteger();
- if (ldivisor != INFLATED) {
- r = mdividend.divide(ldivisor, mq);
- isRemainderZero = (r == 0);
- qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
+ if ((divisor.intCompact != INFLATED)) {
+ return divide(this.intVal, this.scale, divisor.intCompact, divisor.scale, scale, roundingMode);
} else {
- mdivisor = new MutableBigInteger(bdivisor.mag);
- mr = mdividend.divide(mdivisor, mq);
- isRemainderZero = mr.isZero();
- qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
+ return divide(this.intVal, this.scale, divisor.intVal, divisor.scale, scale, roundingMode);
}
}
- boolean increment = false;
- if (!isRemainderZero) {
- int cmpFracHalf;
- /* Round as appropriate */
- if (roundingMode == ROUND_UNNECESSARY) { // Rounding prohibited
- throw new ArithmeticException("Rounding necessary");
- } else if (roundingMode == ROUND_UP) { // Away from zero
- increment = true;
- } else if (roundingMode == ROUND_DOWN) { // Towards zero
- increment = false;
- } else if (roundingMode == ROUND_CEILING) { // Towards +infinity
- increment = (qsign > 0);
- } else if (roundingMode == ROUND_FLOOR) { // Towards -infinity
- increment = (qsign < 0);
- } else {
- if (isLongDivision || ldivisor != INFLATED) {
- if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
- cmpFracHalf = 1; // 2 * r can't fit into long
- } else {
- cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
- }
- } else {
- cmpFracHalf = mr.compareHalf(mdivisor);
- }
- if (cmpFracHalf < 0)
- increment = false; // We're closer to higher digit
- else if (cmpFracHalf > 0) // We're closer to lower digit
- increment = true;
- else if (roundingMode == ROUND_HALF_UP)
- increment = true;
- else if (roundingMode == ROUND_HALF_DOWN)
- increment = false;
- else // roundingMode == ROUND_HALF_EVEN, true iff quotient is odd
- increment = isLongDivision ? (q & 1L) != 0L : mq.isOdd();
- }
- }
- BigDecimal res;
- if (isLongDivision)
- res = new BigDecimal(null, (increment ? q + qsign : q), scale, 0);
- else {
- if (increment)
- mq.add(MutableBigInteger.ONE);
- res = mq.toBigDecimal(qsign, scale);
- }
- if (isRemainderZero && preferredScale != scale)
- res.stripZerosToMatchScale(preferredScale);
- return res;
}
/**
@@ -1541,7 +1628,7 @@
* @see #ROUND_UNNECESSARY
*/
public BigDecimal divide(BigDecimal divisor, int roundingMode) {
- return this.divide(divisor, scale, roundingMode);
+ return this.divide(divisor, scale, roundingMode);
}
/**
@@ -1588,15 +1675,11 @@
}
// Calculate preferred scale
- int preferredScale = saturateLong((long)this.scale - divisor.scale);
- if (this.signum() == 0) // 0/y
- return (preferredScale >= 0 &&
- preferredScale < ZERO_SCALED_BY.length) ?
- ZERO_SCALED_BY[preferredScale] :
- BigDecimal.valueOf(0, preferredScale);
+ int preferredScale = saturateLong((long) this.scale - divisor.scale);
+
+ if (this.signum() == 0) // 0/y
+ return zeroValueOf(preferredScale);
else {
- this.inflate();
- divisor.inflate();
/*
* If the quotient this/divisor has a terminating decimal
* expansion, the expansion can have no more than
@@ -1623,7 +1706,6 @@
// the desired one by removing trailing zeros; since the
// exact divide method does not have an explicit digit
// limit, we can add zeros too.
-
if (preferredScale > quotientScale)
return quotient.setScale(preferredScale, ROUND_UNNECESSARY);
@@ -1668,38 +1750,23 @@
throw new ArithmeticException("Division undefined"); // NaN
throw new ArithmeticException("Division by zero");
}
- if (dividend.signum() == 0) // 0/y
- return new BigDecimal(BigInteger.ZERO, 0,
- saturateLong(preferredScale), 1);
-
- // Normalize dividend & divisor so that both fall into [0.1, 0.999...]
+ if (dividend.signum() == 0) // 0/y
+ return zeroValueOf(saturateLong(preferredScale));
int xscale = dividend.precision();
int yscale = divisor.precision();
- dividend = new BigDecimal(dividend.intVal, dividend.intCompact,
- xscale, xscale);
- divisor = new BigDecimal(divisor.intVal, divisor.intCompact,
- yscale, yscale);
- if (dividend.compareMagnitude(divisor) > 0) // satisfy constraint (b)
- yscale = divisor.scale -= 1; // [that is, divisor *= 10]
-
- // In order to find out whether the divide generates the exact result,
- // we avoid calling the above divide method. 'quotient' holds the
- // return BigDecimal object whose scale will be set to 'scl'.
- BigDecimal quotient;
- int scl = checkScale(preferredScale + yscale - xscale + mcp);
- if (checkScale((long)mcp + yscale) > xscale)
- dividend = dividend.setScale(mcp + yscale, ROUND_UNNECESSARY);
- else
- divisor = divisor.setScale(checkScale((long)xscale - mcp),
- ROUND_UNNECESSARY);
- quotient = divideAndRound(dividend.intCompact, dividend.intVal,
- divisor.intCompact, divisor.intVal,
- scl, mc.roundingMode.oldMode,
- checkScale(preferredScale));
- // doRound, here, only affects 1000000000 case.
- quotient = doRound(quotient, mc);
-
- return quotient;
+ if(dividend.intCompact!=INFLATED) {
+ if(divisor.intCompact!=INFLATED) {
+ return divide(dividend.intCompact, xscale, divisor.intCompact, yscale, preferredScale, mc);
+ } else {
+ return divide(dividend.intCompact, xscale, divisor.intVal, yscale, preferredScale, mc);
+ }
+ } else {
+ if(divisor.intCompact!=INFLATED) {
+ return divide(dividend.intVal, xscale, divisor.intCompact, yscale, preferredScale, mc);
+ } else {
+ return divide(dividend.intVal, xscale, divisor.intVal, yscale, preferredScale, mc);
+ }
+ }
}
/**
@@ -1715,13 +1782,13 @@
*/
public BigDecimal divideToIntegralValue(BigDecimal divisor) {
// Calculate preferred scale
- int preferredScale = saturateLong((long)this.scale - divisor.scale);
+ int preferredScale = saturateLong((long) this.scale - divisor.scale);
if (this.compareMagnitude(divisor) < 0) {
// much faster when this << divisor
- return BigDecimal.valueOf(0, preferredScale);
+ return zeroValueOf(preferredScale);
}
- if(this.signum() == 0 && divisor.signum() != 0)
+ if (this.signum() == 0 && divisor.signum() != 0)
return this.setScale(preferredScale, ROUND_UNNECESSARY);
// Perform a divide with enough digits to round to a correct
@@ -1735,13 +1802,14 @@
RoundingMode.DOWN));
if (quotient.scale > 0) {
quotient = quotient.setScale(0, RoundingMode.DOWN);
- quotient.stripZerosToMatchScale(preferredScale);
+ quotient = stripZerosToMatchScale(quotient.intVal, quotient.intCompact, quotient.scale, preferredScale);
}
if (quotient.scale < preferredScale) {
// pad with zeros if necessary
quotient = quotient.setScale(preferredScale, ROUND_UNNECESSARY);
}
+
return quotient;
}
@@ -1766,8 +1834,8 @@
* @author Joseph D. Darcy
*/
public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) {
- if (mc.precision == 0 || // exact result
- (this.compareMagnitude(divisor) < 0) ) // zero result
+ if (mc.precision == 0 || // exact result
+ (this.compareMagnitude(divisor) < 0)) // zero result
return divideToIntegralValue(divisor);
// Calculate preferred scale
@@ -1780,8 +1848,7 @@
* digits. Next, remove any fractional digits from the
* quotient and adjust the scale to the preferred value.
*/
- BigDecimal result = this.
- divide(divisor, new MathContext(mc.precision, RoundingMode.DOWN));
+ BigDecimal result = this.divide(divisor, new MathContext(mc.precision, RoundingMode.DOWN));
if (result.scale() < 0) {
/*
@@ -1811,8 +1878,7 @@
return result.setScale(result.scale() +
Math.min(precisionDiff, preferredScale - result.scale) );
} else {
- result.stripZerosToMatchScale(preferredScale);
- return result;
+ return stripZerosToMatchScale(result.intVal,result.intCompact,result.scale,preferredScale);
}
}
@@ -1954,8 +2020,7 @@
// No need to calculate pow(n) if result will over/underflow.
// Don't attempt to support "supernormal" numbers.
int newScale = checkScale((long)scale * n);
- this.inflate();
- return new BigDecimal(intVal.pow(n), newScale);
+ return new BigDecimal(this.inflated().pow(n), newScale);
}
@@ -2016,12 +2081,10 @@
throw new ArithmeticException("Invalid operation");
if (n == 0)
return ONE; // x**0 == 1 in X3.274
- this.inflate();
BigDecimal lhs = this;
MathContext workmc = mc; // working settings
int mag = Math.abs(n); // magnitude of n
if (mc.precision > 0) {
-
int elength = longDigitLength(mag); // length of n in digits
if (elength > mc.precision) // X3.274 rule
throw new ArithmeticException("Invalid operation");
@@ -2044,7 +2107,7 @@
// else (!seenbit) no point in squaring ONE
}
// if negative n, calculate the reciprocal using working precision
- if (n<0) // [hence mc.precision>0]
+ if (n < 0) // [hence mc.precision>0]
acc=ONE.divide(acc, workmc);
// round to final precision and strip zeros
return doRound(acc, mc);
@@ -2083,14 +2146,11 @@
* @return {@code -this}.
*/
public BigDecimal negate() {
- BigDecimal result;
- if (intCompact != INFLATED)
- result = BigDecimal.valueOf(-intCompact, scale);
- else {
- result = new BigDecimal(intVal.negate(), scale);
- result.precision = precision;
+ if (intCompact == INFLATED) {
+ return new BigDecimal(intVal.negate(), INFLATED, scale, precision);
+ } else {
+ return valueOf(-intCompact, scale, precision);
}
- return result;
}
/**
@@ -2186,7 +2246,7 @@
if (s != INFLATED)
result = longDigitLength(s);
else
- result = bigDigitLength(inflate());
+ result = bigDigitLength(intVal);
precision = result;
}
return result;
@@ -2202,7 +2262,7 @@
* @since 1.2
*/
public BigInteger unscaledValue() {
- return this.inflate();
+ return this.inflated();
}
// Rounding Modes
@@ -2383,29 +2443,41 @@
if (newScale == oldScale) // easy case
return this;
if (this.signum() == 0) // zero can have any scale
- return BigDecimal.valueOf(0, newScale);
-
- long rs = this.intCompact;
- if (newScale > oldScale) {
- int raise = checkScale((long)newScale - oldScale);
- BigInteger rb = null;
- if (rs == INFLATED ||
- (rs = longMultiplyPowerTen(rs, raise)) == INFLATED)
- rb = bigMultiplyPowerTen(raise);
- return new BigDecimal(rb, rs, newScale,
- (precision > 0) ? precision + raise : 0);
+ return zeroValueOf(newScale);
+ if(this.intCompact!=INFLATED) {
+ long rs = this.intCompact;
+ if (newScale > oldScale) {
+ int raise = checkScale((long) newScale - oldScale);
+ if ((rs = longMultiplyPowerTen(rs, raise)) != INFLATED) {
+ return valueOf(rs,newScale);
+ }
+ BigInteger rb = bigMultiplyPowerTen(raise);
+ return new BigDecimal(rb, INFLATED, newScale, (precision > 0) ? precision + raise : 0);
+ } else {
+ // newScale < oldScale -- drop some digits
+ // Can't predict the precision due to the effect of rounding.
+ int drop = checkScale((long) oldScale - newScale);
+ if (drop < LONG_TEN_POWERS_TABLE.length) {
+ return divideAndRound(rs, LONG_TEN_POWERS_TABLE[drop], newScale, roundingMode, newScale);
+ } else {
+ return divideAndRound(this.inflated(), bigTenToThe(drop), newScale, roundingMode, newScale);
+ }
+ }
} else {
- // newScale < oldScale -- drop some digits
- // Can't predict the precision due to the effect of rounding.
- int drop = checkScale((long)oldScale - newScale);
- if (drop < LONG_TEN_POWERS_TABLE.length)
- return divideAndRound(rs, this.intVal,
- LONG_TEN_POWERS_TABLE[drop], null,
- newScale, roundingMode, newScale);
- else
- return divideAndRound(rs, this.intVal,
- INFLATED, bigTenToThe(drop),
- newScale, roundingMode, newScale);
+ if (newScale > oldScale) {
+ int raise = checkScale((long) newScale - oldScale);
+ BigInteger rb = bigMultiplyPowerTen(this.intVal,raise);
+ return new BigDecimal(rb, INFLATED, newScale, (precision > 0) ? precision + raise : 0);
+ } else {
+ // newScale < oldScale -- drop some digits
+ // Can't predict the precision due to the effect of rounding.
+ int drop = checkScale((long) oldScale - newScale);
+ if (drop < LONG_TEN_POWERS_TABLE.length)
+ return divideAndRound(this.intVal, LONG_TEN_POWERS_TABLE[drop], newScale, roundingMode,
+ newScale);
+ else
+ return divideAndRound(this.intVal, bigTenToThe(drop), newScale, roundingMode, newScale);
+ }
}
}
@@ -2524,10 +2596,11 @@
* @since 1.5
*/
public BigDecimal stripTrailingZeros() {
- this.inflate();
- BigDecimal result = new BigDecimal(intVal, scale);
- result.stripZerosToMatchScale(Long.MIN_VALUE);
- return result;
+ if(intCompact!=INFLATED) {
+ return createAndStripZerosToMatchScale(intCompact, scale, Long.MIN_VALUE);
+ } else {
+ return createAndStripZerosToMatchScale(intVal, scale, Long.MIN_VALUE);
+ }
}
// Comparison Operations
@@ -2647,7 +2720,7 @@
} else if (xs != INFLATED)
return xs == compactValFor(this.intVal);
- return this.inflate().equals(xDec.inflate());
+ return this.inflated().equals(xDec.inflated());
}
/**
@@ -2872,13 +2945,38 @@
* @see #toEngineeringString()
*/
public String toPlainString() {
- BigDecimal bd = this;
- if (bd.scale < 0)
- bd = bd.setScale(0);
- bd.inflate();
- if (bd.scale == 0) // No decimal point
- return bd.intVal.toString();
- return bd.getValueString(bd.signum(), bd.intVal.abs().toString(), bd.scale);
+ if(scale==0) {
+ if(intCompact!=INFLATED) {
+ return Long.toString(intCompact);
+ } else {
+ return intVal.toString();
+ }
+ }
+ if(this.scale<0) { // No decimal point
+ if(signum()==0) {
+ return "0";
+ }
+ int tailingZeros = checkScaleNonZero((-(long)scale));
+ StringBuilder buf;
+ if(intCompact!=INFLATED) {
+ buf = new StringBuilder(20+tailingZeros);
+ buf.append(intCompact);
+ } else {
+ String str = intVal.toString();
+ buf = new StringBuilder(str.length()+tailingZeros);
+ buf.append(str);
+ }
+ for (int i = 0; i < tailingZeros; i++)
+ buf.append('0');
+ return buf.toString();
+ }
+ String str ;
+ if(intCompact!=INFLATED) {
+ str = Long.toString(Math.abs(intCompact));
+ } else {
+ str = intVal.abs().toString();
+ }
+ return getValueString(signum(), str, scale);
}
/* Returns a digit.digit string */
@@ -2922,7 +3020,7 @@
*/
public BigInteger toBigInteger() {
// force to an integer, quietly
- return this.setScale(0, ROUND_DOWN).inflate();
+ return this.setScale(0, ROUND_DOWN).inflated();
}
/**
@@ -2937,7 +3035,7 @@
*/
public BigInteger toBigIntegerExact() {
// round to an integer, with Exception if decimal part non-0
- return this.setScale(0, ROUND_UNNECESSARY).inflate();
+ return this.setScale(0, ROUND_UNNECESSARY).inflated();
}
/**
@@ -2990,7 +3088,7 @@
BigDecimal num = this.setScale(0, ROUND_UNNECESSARY);
if (num.precision() >= 19) // need to check carefully
LongOverflow.check(num);
- return num.inflate().longValue();
+ return num.inflated().longValue();
}
private static class LongOverflow {
@@ -3001,9 +3099,9 @@
private static final BigInteger LONGMAX = BigInteger.valueOf(Long.MAX_VALUE);
public static void check(BigDecimal num) {
- num.inflate();
- if ((num.intVal.compareTo(LONGMIN) < 0) ||
- (num.intVal.compareTo(LONGMAX) > 0))
+ BigInteger intVal = num.inflated();
+ if (intVal.compareTo(LONGMIN) < 0 ||
+ intVal.compareTo(LONGMAX) > 0)
throw new java.lang.ArithmeticException("Overflow");
}
}
@@ -3107,8 +3205,28 @@
* @return this {@code BigDecimal} converted to a {@code float}.
*/
public float floatValue(){
- if (scale == 0 && intCompact != INFLATED)
+ if(intCompact != INFLATED) {
+ if (scale == 0) {
return (float)intCompact;
+ } else {
+ /*
+ * If both intCompact and the scale can be exactly
+ * represented as float values, perform a single float
+ * multiply or divide to compute the (properly
+ * rounded) result.
+ */
+ if (Math.abs(intCompact) < 1L<<22 ) {
+ // Don't have too guard against
+ // Math.abs(MIN_VALUE) because of outer check
+ // against INFLATED.
+ if (scale > 0 && scale < float10pow.length) {
+ return (float)intCompact / float10pow[scale];
+ } else if (scale < 0 && scale > -float10pow.length) {
+ return (float)intCompact * float10pow[-scale];
+ }
+ }
+ }
+ }
// Somewhat inefficient, but guaranteed to work.
return Float.parseFloat(this.toString());
}
@@ -3130,13 +3248,53 @@
* @return this {@code BigDecimal} converted to a {@code double}.
*/
public double doubleValue(){
- if (scale == 0 && intCompact != INFLATED)
- return (double)intCompact;
+ if(intCompact != INFLATED) {
+ if (scale == 0) {
+ return (double)intCompact;
+ } else {
+ /*
+ * If both intCompact and the scale can be exactly
+ * represented as double values, perform a single
+ * double multiply or divide to compute the (properly
+ * rounded) result.
+ */
+ if (Math.abs(intCompact) < 1L<<52 ) {
+ // Don't have too guard against
+ // Math.abs(MIN_VALUE) because of outer check
+ // against INFLATED.
+ if (scale > 0 && scale < double10pow.length) {
+ return (double)intCompact / double10pow[scale];
+ } else if (scale < 0 && scale > -double10pow.length) {
+ return (double)intCompact * double10pow[-scale];
+ }
+ }
+ }
+ }
// Somewhat inefficient, but guaranteed to work.
return Double.parseDouble(this.toString());
}
/**
+ * Powers of 10 which can be represented exactly in {@code
+ * double}.
+ */
+ private static final double double10pow[] = {
+ 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5,
+ 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10, 1.0e11,
+ 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17,
+ 1.0e18, 1.0e19, 1.0e20, 1.0e21, 1.0e22
+ };
+
+ /**
+ * Powers of 10 which can be represented exactly in {@code
+ * float}.
+ */
+ private static final float float10pow[] = {
+ 1.0e0f, 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
+ 1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
+ };
+
+ /**
* Returns the size of an ulp, a unit in the last place, of this
* {@code BigDecimal}. An ulp of a nonzero {@code BigDecimal}
* value is the positive distance between this value and the
@@ -3151,10 +3309,9 @@
* @since 1.5
*/
public BigDecimal ulp() {
- return BigDecimal.valueOf(1, this.scale());
+ return BigDecimal.valueOf(1, this.scale(), 1);
}
-
// Private class to build a string representation for BigDecimal object.
// "StringBuilderHelper" is constructed as a thread local variable so it is
// thread safe. The StringBuilder field acts as a buffer to hold the temporary
@@ -3268,6 +3425,15 @@
return (intCompact != INFLATED) ?
Long.toString(intCompact):
intVal.toString();
+ if (scale == 2 &&
+ intCompact >= 0 && intCompact < Integer.MAX_VALUE) {
+ // currency fast path
+ int lowInt = (int)intCompact % 100;
+ int highInt = (int)intCompact / 100;
+ return (Integer.toString(highInt) + '.' +
+ StringBuilderHelper.DIGIT_TENS[lowInt] +
+ StringBuilderHelper.DIGIT_ONES[lowInt]) ;
+ }
StringBuilderHelper sbHelper = threadLocalStringBuilderHelper.get();
char[] coeff;
@@ -3377,7 +3543,7 @@
tenpow[0] = '1';
for (int i = 1; i <= n; i++)
tenpow[i] = '0';
- return new BigInteger(tenpow);
+ return new BigInteger(tenpow,1, tenpow.length);
}
/**
@@ -3433,11 +3599,16 @@
1000000000000000000L // 18 / 10^18
};
- private static volatile BigInteger BIG_TEN_POWERS_TABLE[] = {BigInteger.ONE,
- BigInteger.valueOf(10), BigInteger.valueOf(100),
- BigInteger.valueOf(1000), BigInteger.valueOf(10000),
- BigInteger.valueOf(100000), BigInteger.valueOf(1000000),
- BigInteger.valueOf(10000000), BigInteger.valueOf(100000000),
+ private static volatile BigInteger BIG_TEN_POWERS_TABLE[] = {
+ BigInteger.ONE,
+ BigInteger.valueOf(10),
+ BigInteger.valueOf(100),
+ BigInteger.valueOf(1000),
+ BigInteger.valueOf(10000),
+ BigInteger.valueOf(100000),
+ BigInteger.valueOf(1000000),
+ BigInteger.valueOf(10000000),
+ BigInteger.valueOf(100000000),
BigInteger.valueOf(1000000000),
BigInteger.valueOf(10000000000L),
BigInteger.valueOf(100000000000L),
@@ -3502,7 +3673,7 @@
*/
private BigInteger bigMultiplyPowerTen(int n) {
if (n <= 0)
- return this.inflate();
+ return this.inflated();
if (intCompact != INFLATED)
return bigTenToThe(n).multiply(intCompact);
@@ -3511,12 +3682,13 @@
}
/**
- * Assign appropriate BigInteger to intVal field if intVal is
+ * Returns appropriate BigInteger from intVal field if intVal is
* null, i.e. the compact representation is in use.
*/
- private BigInteger inflate() {
- if (intVal == null)
- intVal = BigInteger.valueOf(intCompact);
+ private BigInteger inflated() {
+ if (intVal == null) {
+ return BigInteger.valueOf(intCompact);
+ }
return intVal;
}
@@ -3543,6 +3715,30 @@
}
}
+ private static class UnsafeHolder {
+ private static final sun.misc.Unsafe unsafe;
+ private static final long intCompactOffset;
+ private static final long intValOffset;
+ static {
+ try {
+ unsafe = sun.misc.Unsafe.getUnsafe();
+ intCompactOffset = unsafe.objectFieldOffset
+ (BigDecimal.class.getDeclaredField("intCompact"));
+ intValOffset = unsafe.objectFieldOffset
+ (BigDecimal.class.getDeclaredField("intVal"));
+ } catch (Exception ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+ static void setIntCompactVolatile(BigDecimal bd, long val) {
+ unsafe.putLongVolatile(bd, intCompactOffset, val);
+ }
+
+ static void setIntValVolatile(BigDecimal bd, BigInteger val) {
+ unsafe.putObjectVolatile(bd, intValOffset, val);
+ }
+ }
+
/**
* Reconstitute the {@code BigDecimal} instance from a stream (that is,
* deserialize it).
@@ -3559,7 +3755,7 @@
throw new java.io.StreamCorruptedException(message);
// [all values of scale are now allowed]
}
- intCompact = compactValFor(intVal);
+ UnsafeHolder.setIntCompactVolatile(this, compactValFor(intVal));
}
/**
@@ -3570,13 +3766,12 @@
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Must inflate to maintain compatible serial form.
- this.inflate();
-
- // Write proper fields
+ if (this.intVal == null)
+ UnsafeHolder.setIntValVolatile(this, BigInteger.valueOf(this.intCompact));
+ // Could reset intVal back to null if it has to be set.
s.defaultWriteObject();
}
-
/**
* Returns the length of the absolute value of a {@code long}, in decimal
* digits.
@@ -3584,36 +3779,29 @@
* @param x the {@code long}
* @return the length of the unscaled value, in deciaml digits.
*/
- private static int longDigitLength(long x) {
+ static int longDigitLength(long x) {
/*
* As described in "Bit Twiddling Hacks" by Sean Anderson,
* (http://graphics.stanford.edu/~seander/bithacks.html)
- * integer log 10 of x is within 1 of
- * (1233/4096)* (1 + integer log 2 of x).
- * The fraction 1233/4096 approximates log10(2). So we first
- * do a version of log2 (a variant of Long class with
- * pre-checks and opposite directionality) and then scale and
- * check against powers table. This is a little simpler in
- * present context than the version in Hacker's Delight sec
- * 11-4. Adding one to bit length allows comparing downward
- * from the LONG_TEN_POWERS_TABLE that we need anyway.
+ * integer log 10 of x is within 1 of (1233/4096)* (1 +
+ * integer log 2 of x). The fraction 1233/4096 approximates
+ * log10(2). So we first do a version of log2 (a variant of
+ * Long class with pre-checks and opposite directionality) and
+ * then scale and check against powers table. This is a little
+ * simpler in present context than the version in Hacker's
+ * Delight sec 11-4. Adding one to bit length allows comparing
+ * downward from the LONG_TEN_POWERS_TABLE that we need
+ * anyway.
*/
- assert x != INFLATED;
+ assert x != BigDecimal.INFLATED;
if (x < 0)
x = -x;
if (x < 10) // must screen for 0, might as well 10
return 1;
- int n = 64; // not 63, to avoid needing to add 1 later
- int y = (int)(x >>> 32);
- if (y == 0) { n -= 32; y = (int)x; }
- if (y >>> 16 == 0) { n -= 16; y <<= 16; }
- if (y >>> 24 == 0) { n -= 8; y <<= 8; }
- if (y >>> 28 == 0) { n -= 4; y <<= 4; }
- if (y >>> 30 == 0) { n -= 2; y <<= 2; }
- int r = (((y >>> 31) + n) * 1233) >>> 12;
+ int r = ((64 - Long.numberOfLeadingZeros(x) + 1) * 1233) >>> 12;
long[] tab = LONG_TEN_POWERS_TABLE;
// if r >= length, must have max possible digits for long
- return (r >= tab.length || x < tab[r])? r : r+1;
+ return (r >= tab.length || x < tab[r]) ? r : r + 1;
}
/**
@@ -3635,41 +3823,6 @@
return b.compareMagnitude(bigTenToThe(r)) < 0? r : r+1;
}
-
- /**
- * Remove insignificant trailing zeros from this
- * {@code BigDecimal} until the preferred scale is reached or no
- * more zeros can be removed. If the preferred scale is less than
- * Integer.MIN_VALUE, all the trailing zeros will be removed.
- *
- * {@code BigInteger} assistance could help, here?
- *
- * <p>WARNING: This method should only be called on new objects as
- * it mutates the value fields.
- *
- * @return this {@code BigDecimal} with a scale possibly reduced
- * to be closed to the preferred scale.
- */
- private BigDecimal stripZerosToMatchScale(long preferredScale) {
- this.inflate();
- BigInteger qr[]; // quotient-remainder pair
- while ( intVal.compareMagnitude(BigInteger.TEN) >= 0 &&
- scale > preferredScale) {
- if (intVal.testBit(0))
- break; // odd number cannot end in 0
- qr = intVal.divideAndRemainder(BigInteger.TEN);
- if (qr[1].signum() != 0)
- break; // non-0 remainder
- intVal=qr[0];
- scale = checkScale((long)scale-1); // could Overflow
- if (precision > 0) // adjust precision if known
- precision--;
- }
- if (intVal != null)
- intCompact = compactValFor(intVal);
- return this;
- }
-
/**
* Check a scale for Underflow or Overflow. If this BigDecimal is
* nonzero, throw an exception if the scale is outof range. If this
@@ -3693,74 +3846,7 @@
return asInt;
}
- /**
- * Round an operand; used only if digits > 0. Does not change
- * {@code this}; if rounding is needed a new {@code BigDecimal}
- * is created and returned.
- *
- * @param mc the context to use.
- * @throws ArithmeticException if the result is inexact but the
- * rounding mode is {@code UNNECESSARY}.
- */
- private BigDecimal roundOp(MathContext mc) {
- BigDecimal rounded = doRound(this, mc);
- return rounded;
- }
-
- /** Round this BigDecimal according to the MathContext settings;
- * used only if precision {@literal >} 0.
- *
- * <p>WARNING: This method should only be called on new objects as
- * it mutates the value fields.
- *
- * @param mc the context to use.
- * @throws ArithmeticException if the rounding mode is
- * {@code RoundingMode.UNNECESSARY} and the
- * {@code BigDecimal} operation would require rounding.
- */
- private void roundThis(MathContext mc) {
- BigDecimal rounded = doRound(this, mc);
- if (rounded == this) // wasn't rounded
- return;
- this.intVal = rounded.intVal;
- this.intCompact = rounded.intCompact;
- this.scale = rounded.scale;
- this.precision = rounded.precision;
- }
-
- /**
- * Returns a {@code BigDecimal} rounded according to the
- * MathContext settings; used only if {@code mc.precision > 0}.
- * Does not change {@code this}; if rounding is needed a new
- * {@code BigDecimal} is created and returned.
- *
- * @param mc the context to use.
- * @return a {@code BigDecimal} rounded according to the MathContext
- * settings. May return this, if no rounding needed.
- * @throws ArithmeticException if the rounding mode is
- * {@code RoundingMode.UNNECESSARY} and the
- * result is inexact.
- */
- private static BigDecimal doRound(BigDecimal d, MathContext mc) {
- int mcp = mc.precision;
- int drop;
- // This might (rarely) iterate to cover the 999=>1000 case
- while ((drop = d.precision() - mcp) > 0) {
- int newScale = d.checkScale((long)d.scale - drop);
- int mode = mc.roundingMode.oldMode;
- if (drop < LONG_TEN_POWERS_TABLE.length)
- d = divideAndRound(d.intCompact, d.intVal,
- LONG_TEN_POWERS_TABLE[drop], null,
- newScale, mode, newScale);
- else
- d = divideAndRound(d.intCompact, d.intVal,
- INFLATED, bigTenToThe(drop),
- newScale, mode, newScale);
- }
- return d;
- }
-
- /**
+ /**
* Returns the compact value for given {@code BigInteger}, or
* INFLATED if too big. Relies on internal representation of
* {@code BigInteger}.
@@ -3852,4 +3938,1290 @@
}
return this;
}
+
+ /* the same as checkScale where value!=0 */
+ private static int checkScaleNonZero(long val) {
+ int asInt = (int)val;
+ if (asInt != val) {
+ throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
+ }
+ return asInt;
+ }
+
+ private static int checkScale(long intCompact, long val) {
+ int asInt = (int)val;
+ if (asInt != val) {
+ asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
+ if (intCompact != 0)
+ throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
+ }
+ return asInt;
+ }
+
+ private static int checkScale(BigInteger intVal, long val) {
+ int asInt = (int)val;
+ if (asInt != val) {
+ asInt = val>Integer.MAX_VALUE ? Integer.MAX_VALUE : Integer.MIN_VALUE;
+ if (intVal.signum() != 0)
+ throw new ArithmeticException(asInt>0 ? "Underflow":"Overflow");
+ }
+ return asInt;
+ }
+
+ /**
+ * Returns a {@code BigDecimal} rounded according to the MathContext
+ * settings;
+ * If rounding is needed a new {@code BigDecimal} is created and returned.
+ *
+ * @param val the value to be rounded
+ * @param mc the context to use.
+ * @return a {@code BigDecimal} rounded according to the MathContext
+ * settings. May return {@code value}, if no rounding needed.
+ * @throws ArithmeticException if the rounding mode is
+ * {@code RoundingMode.UNNECESSARY} and the
+ * result is inexact.
+ */
+ private static BigDecimal doRound(BigDecimal val, MathContext mc) {
+ int mcp = mc.precision;
+ boolean wasDivided = false;
+ if (mcp > 0) {
+ BigInteger intVal = val.intVal;
+ long compactVal = val.intCompact;
+ int scale = val.scale;
+ int prec = val.precision();
+ int mode = mc.roundingMode.oldMode;
+ int drop;
+ if (compactVal == INFLATED) {
+ drop = prec - mcp;
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ intVal = divideAndRoundByTenPow(intVal, drop, mode);
+ wasDivided = true;
+ compactVal = compactValFor(intVal);
+ if (compactVal != INFLATED) {
+ prec = longDigitLength(compactVal);
+ break;
+ }
+ prec = bigDigitLength(intVal);
+ drop = prec - mcp;
+ }
+ }
+ if (compactVal != INFLATED) {
+ drop = prec - mcp; // drop can't be more than 18
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
+ wasDivided = true;
+ prec = longDigitLength(compactVal);
+ drop = prec - mcp;
+ intVal = null;
+ }
+ }
+ return wasDivided ? new BigDecimal(intVal,compactVal,scale,prec) : val;
+ }
+ return val;
+ }
+
+ /*
+ * Returns a {@code BigDecimal} created from {@code long} value with
+ * given scale rounded according to the MathContext settings
+ */
+ private static BigDecimal doRound(long compactVal, int scale, MathContext mc) {
+ int mcp = mc.precision;
+ if (mcp > 0 && mcp < 19) {
+ int prec = longDigitLength(compactVal);
+ int drop = prec - mcp; // drop can't be more than 18
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
+ prec = longDigitLength(compactVal);
+ drop = prec - mcp;
+ }
+ return valueOf(compactVal, scale, prec);
+ }
+ return valueOf(compactVal, scale);
+ }
+
+ /*
+ * Returns a {@code BigDecimal} created from {@code BigInteger} value with
+ * given scale rounded according to the MathContext settings
+ */
+ private static BigDecimal doRound(BigInteger intVal, int scale, MathContext mc) {
+ int mcp = mc.precision;
+ int prec = 0;
+ if (mcp > 0) {
+ long compactVal = compactValFor(intVal);
+ int mode = mc.roundingMode.oldMode;
+ int drop;
+ if (compactVal == INFLATED) {
+ prec = bigDigitLength(intVal);
+ drop = prec - mcp;
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ intVal = divideAndRoundByTenPow(intVal, drop, mode);
+ compactVal = compactValFor(intVal);
+ if (compactVal != INFLATED) {
+ break;
+ }
+ prec = bigDigitLength(intVal);
+ drop = prec - mcp;
+ }
+ }
+ if (compactVal != INFLATED) {
+ prec = longDigitLength(compactVal);
+ drop = prec - mcp; // drop can't be more than 18
+ while (drop > 0) {
+ scale = checkScaleNonZero((long) scale - drop);
+ compactVal = divideAndRound(compactVal, LONG_TEN_POWERS_TABLE[drop], mc.roundingMode.oldMode);
+ prec = longDigitLength(compactVal);
+ drop = prec - mcp;
+ }
+ return valueOf(compactVal,scale,prec);
+ }
+ }
+ return new BigDecimal(intVal,INFLATED,scale,prec);
+ }
+
+ /*
+ * Divides {@code BigInteger} value by ten power.
+ */
+ private static BigInteger divideAndRoundByTenPow(BigInteger intVal, int tenPow, int roundingMode) {
+ if (tenPow < LONG_TEN_POWERS_TABLE.length)
+ intVal = divideAndRound(intVal, LONG_TEN_POWERS_TABLE[tenPow], roundingMode);
+ else
+ intVal = divideAndRound(intVal, bigTenToThe(tenPow), roundingMode);
+ return intVal;
+ }
+
+ /**
+ * Internally used for division operation for division {@code long} by
+ * {@code long}.
+ * The returned {@code BigDecimal} object is the quotient whose scale is set
+ * to the passed in scale. If the remainder is not zero, it will be rounded
+ * based on the passed in roundingMode. Also, if the remainder is zero and
+ * the last parameter, i.e. preferredScale is NOT equal to scale, the
+ * trailing zeros of the result is stripped to match the preferredScale.
+ */
+ private static BigDecimal divideAndRound(long ldividend, long ldivisor, int scale, int roundingMode,
+ int preferredScale) {
+
+ int qsign; // quotient sign
+ long q = ldividend / ldivisor; // store quotient in long
+ if (roundingMode == ROUND_DOWN && scale == preferredScale)
+ return valueOf(q, scale);
+ long r = ldividend % ldivisor; // store remainder in long
+ qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
+ if (r != 0) {
+ boolean increment = needIncrement(ldivisor, roundingMode, qsign, q, r);
+ return valueOf((increment ? q + qsign : q), scale);
+ } else {
+ if (preferredScale != scale)
+ return createAndStripZerosToMatchScale(q, scale, preferredScale);
+ else
+ return valueOf(q, scale);
+ }
+ }
+
+ /**
+ * Divides {@code long} by {@code long} and do rounding based on the
+ * passed in roundingMode.
+ */
+ private static long divideAndRound(long ldividend, long ldivisor, int roundingMode) {
+ int qsign; // quotient sign
+ long q = ldividend / ldivisor; // store quotient in long
+ if (roundingMode == ROUND_DOWN)
+ return q;
+ long r = ldividend % ldivisor; // store remainder in long
+ qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;
+ if (r != 0) {
+ boolean increment = needIncrement(ldivisor, roundingMode, qsign, q, r);
+ return increment ? q + qsign : q;
+ } else {
+ return q;
+ }
+ }
+
+ /**
+ * Shared logic of need increment computation.
+ */
+ private static boolean commonNeedIncrement(int roundingMode, int qsign,
+ int cmpFracHalf, boolean oddQuot) {
+ switch(roundingMode) {
+ case ROUND_UNNECESSARY:
+ throw new ArithmeticException("Rounding necessary");
+
+ case ROUND_UP: // Away from zero
+ return true;
+
+ case ROUND_DOWN: // Towards zero
+ return false;
+
+ case ROUND_CEILING: // Towards +infinity
+ return qsign > 0;
+
+ case ROUND_FLOOR: // Towards -infinity
+ return qsign < 0;
+
+ default: // Some kind of half-way rounding
+ assert roundingMode >= ROUND_HALF_UP &&
+ roundingMode <= ROUND_HALF_EVEN: "Unexpected rounding mode" + RoundingMode.valueOf(roundingMode);
+
+ if (cmpFracHalf < 0 ) // We're closer to higher digit
+ return false;
+ else if (cmpFracHalf > 0 ) // We're closer to lower digit
+ return true;
+ else { // half-way
+ assert cmpFracHalf == 0;
+
+ switch(roundingMode) {
+ case ROUND_HALF_DOWN:
+ return false;
+
+ case ROUND_HALF_UP:
+ return true;
+
+ case ROUND_HALF_EVEN:
+ return oddQuot;
+
+ default:
+ throw new AssertionError("Unexpected rounding mode" + roundingMode);
+ }
+ }
+ }
+ }
+
+ /**
+ * Tests if quotient has to be incremented according the roundingMode
+ */
+ private static boolean needIncrement(long ldivisor, int roundingMode,
+ int qsign, long q, long r) {
+ assert r != 0L;
+
+ int cmpFracHalf;
+ if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
+ cmpFracHalf = 1; // 2 * r can't fit into long
+ } else {
+ cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
+ }
+
+ return commonNeedIncrement(roundingMode, qsign, cmpFracHalf, (q & 1L) != 0L);
+ }
+
+ /**
+ * Divides {@code BigInteger} value by {@code long} value and
+ * do rounding based on the passed in roundingMode.
+ */
+ private static BigInteger divideAndRound(BigInteger bdividend, long ldivisor, int roundingMode) {
+ boolean isRemainderZero; // record remainder is zero or not
+ int qsign; // quotient sign
+ long r = 0; // store quotient & remainder in long
+ MutableBigInteger mq = null; // store quotient
+ // Descend into mutables for faster remainder checks
+ MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
+ mq = new MutableBigInteger();
+ r = mdividend.divide(ldivisor, mq);
+ isRemainderZero = (r == 0);
+ qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
+ if (!isRemainderZero) {
+ if(needIncrement(ldivisor, roundingMode, qsign, mq, r)) {
+ mq.add(MutableBigInteger.ONE);
+ }
+ }
+ return mq.toBigInteger(qsign);
+ }
+
+ /**
+ * Internally used for division operation for division {@code BigInteger}
+ * by {@code long}.
+ * The returned {@code BigDecimal} object is the quotient whose scale is set
+ * to the passed in scale. If the remainder is not zero, it will be rounded
+ * based on the passed in roundingMode. Also, if the remainder is zero and
+ * the last parameter, i.e. preferredScale is NOT equal to scale, the
+ * trailing zeros of the result is stripped to match the preferredScale.
+ */
+ private static BigDecimal divideAndRound(BigInteger bdividend,
+ long ldivisor, int scale, int roundingMode, int preferredScale) {
+ boolean isRemainderZero; // record remainder is zero or not
+ int qsign; // quotient sign
+ long r = 0; // store quotient & remainder in long
+ MutableBigInteger mq = null; // store quotient
+ // Descend into mutables for faster remainder checks
+ MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
+ mq = new MutableBigInteger();
+ r = mdividend.divide(ldivisor, mq);
+ isRemainderZero = (r == 0);
+ qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;
+ if (!isRemainderZero) {
+ if(needIncrement(ldivisor, roundingMode, qsign, mq, r)) {
+ mq.add(MutableBigInteger.ONE);
+ }
+ return mq.toBigDecimal(qsign, scale);
+ } else {
+ if (preferredScale != scale) {
+ long compactVal = mq.toCompactValue(qsign);
+ if(compactVal!=INFLATED) {
+ return createAndStripZerosToMatchScale(compactVal, scale, preferredScale);
+ }
+ BigInteger intVal = mq.toBigInteger(qsign);
+ return createAndStripZerosToMatchScale(intVal,scale, preferredScale);
+ } else {
+ return mq.toBigDecimal(qsign, scale);
+ }
+ }
+ }
+
+ /**
+ * Tests if quotient has to be incremented according the roundingMode
+ */
+ private static boolean needIncrement(long ldivisor, int roundingMode,
+ int qsign, MutableBigInteger mq, long r) {
+ assert r != 0L;
+
+ int cmpFracHalf;
+ if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {
+ cmpFracHalf = 1; // 2 * r can't fit into long
+ } else {
+ cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);
+ }
+
+ return commonNeedIncrement(roundingMode, qsign, cmpFracHalf, mq.isOdd());
+ }
+
+ /**
+ * Divides {@code BigInteger} value by {@code BigInteger} value and
+ * do rounding based on the passed in roundingMode.
+ */
+ private static BigInteger divideAndRound(BigInteger bdividend, BigInteger bdivisor, int roundingMode) {
+ boolean isRemainderZero; // record remainder is zero or not
+ int qsign; // quotient sign
+ // Descend into mutables for faster remainder checks
+ MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
+ MutableBigInteger mq = new MutableBigInteger();
+ MutableBigInteger mdivisor = new MutableBigInteger(bdivisor.mag);
+ MutableBigInteger mr = mdividend.divide(mdivisor, mq);
+ isRemainderZero = mr.isZero();
+ qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
+ if (!isRemainderZero) {
+ if (needIncrement(mdivisor, roundingMode, qsign, mq, mr)) {
+ mq.add(MutableBigInteger.ONE);
+ }
+ }
+ return mq.toBigInteger(qsign);
+ }
+
+ /**
+ * Internally used for division operation for division {@code BigInteger}
+ * by {@code BigInteger}.
+ * The returned {@code BigDecimal} object is the quotient whose scale is set
+ * to the passed in scale. If the remainder is not zero, it will be rounded
+ * based on the passed in roundingMode. Also, if the remainder is zero and
+ * the last parameter, i.e. preferredScale is NOT equal to scale, the
+ * trailing zeros of the result is stripped to match the preferredScale.
+ */
+ private static BigDecimal divideAndRound(BigInteger bdividend, BigInteger bdivisor, int scale, int roundingMode,
+ int preferredScale) {
+ boolean isRemainderZero; // record remainder is zero or not
+ int qsign; // quotient sign
+ // Descend into mutables for faster remainder checks
+ MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);
+ MutableBigInteger mq = new MutableBigInteger();
+ MutableBigInteger mdivisor = new MutableBigInteger(bdivisor.mag);
+ MutableBigInteger mr = mdividend.divide(mdivisor, mq);
+ isRemainderZero = mr.isZero();
+ qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;
+ if (!isRemainderZero) {
+ if (needIncrement(mdivisor, roundingMode, qsign, mq, mr)) {
+ mq.add(MutableBigInteger.ONE);
+ }
+ return mq.toBigDecimal(qsign, scale);
+ } else {
+ if (preferredScale != scale) {
+ long compactVal = mq.toCompactValue(qsign);
+ if (compactVal != INFLATED) {
+ return createAndStripZerosToMatchScale(compactVal, scale, preferredScale);
+ }
+ BigInteger intVal = mq.toBigInteger(qsign);
+ return createAndStripZerosToMatchScale(intVal, scale, preferredScale);
+ } else {
+ return mq.toBigDecimal(qsign, scale);
+ }
+ }
+ }
+
+ /**
+ * Tests if quotient has to be incremented according the roundingMode
+ */
+ private static boolean needIncrement(MutableBigInteger mdivisor, int roundingMode,
+ int qsign, MutableBigInteger mq, MutableBigInteger mr) {
+ assert !mr.isZero();
+ int cmpFracHalf = mr.compareHalf(mdivisor);
+ return commonNeedIncrement(roundingMode, qsign, cmpFracHalf, mq.isOdd());
+ }
+
+ /**
+ * Remove insignificant trailing zeros from this
+ * {@code BigInteger} value until the preferred scale is reached or no
+ * more zeros can be removed. If the preferred scale is less than
+ * Integer.MIN_VALUE, all the trailing zeros will be removed.
+ *
+ * @return new {@code BigDecimal} with a scale possibly reduced
+ * to be closed to the preferred scale.
+ */
+ private static BigDecimal createAndStripZerosToMatchScale(BigInteger intVal, int scale, long preferredScale) {
+ BigInteger qr[]; // quotient-remainder pair
+ while (intVal.compareMagnitude(BigInteger.TEN) >= 0
+ && scale > preferredScale) {
+ if (intVal.testBit(0))
+ break; // odd number cannot end in 0
+ qr = intVal.divideAndRemainder(BigInteger.TEN);
+ if (qr[1].signum() != 0)
+ break; // non-0 remainder
+ intVal = qr[0];
+ scale = checkScale(intVal,(long) scale - 1); // could Overflow
+ }
+ return valueOf(intVal, scale, 0);
+ }
+
+ /**
+ * Remove insignificant trailing zeros from this
+ * {@code long} value until the preferred scale is reached or no
+ * more zeros can be removed. If the preferred scale is less than
+ * Integer.MIN_VALUE, all the trailing zeros will be removed.
+ *
+ * @return new {@code BigDecimal} with a scale possibly reduced
+ * to be closed to the preferred scale.
+ */
+ private static BigDecimal createAndStripZerosToMatchScale(long compactVal, int scale, long preferredScale) {
+ while (Math.abs(compactVal) >= 10L && scale > preferredScale) {
+ if ((compactVal & 1L) != 0L)
+ break; // odd number cannot end in 0
+ long r = compactVal % 10L;
+ if (r != 0L)
+ break; // non-0 remainder
+ compactVal /= 10;
+ scale = checkScale(compactVal, (long) scale - 1); // could Overflow
+ }
+ return valueOf(compactVal, scale);
+ }
+
+ private static BigDecimal stripZerosToMatchScale(BigInteger intVal, long intCompact, int scale, int preferredScale) {
+ if(intCompact!=INFLATED) {
+ return createAndStripZerosToMatchScale(intCompact, scale, preferredScale);
+ } else {
+ return createAndStripZerosToMatchScale(intVal==null ? INFLATED_BIGINT : intVal,
+ scale, preferredScale);
+ }
+ }
+
+ /*
+ * returns INFLATED if oveflow
+ */
+ private static long add(long xs, long ys){
+ long sum = xs + ys;
+ // See "Hacker's Delight" section 2-12 for explanation of
+ // the overflow test.
+ if ( (((sum ^ xs) & (sum ^ ys))) >= 0L) { // not overflowed
+ return sum;
+ }
+ return INFLATED;
+ }
+
+ private static BigDecimal add(long xs, long ys, int scale){
+ long sum = add(xs, ys);
+ if (sum!=INFLATED)
+ return BigDecimal.valueOf(sum, scale);
+ return new BigDecimal(BigInteger.valueOf(xs).add(ys), scale);
+ }
+
+ private static BigDecimal add(final long xs, int scale1, final long ys, int scale2) {
+ long sdiff = (long) scale1 - scale2;
+ if (sdiff == 0) {
+ return add(xs, ys, scale1);
+ } else if (sdiff < 0) {
+ int raise = checkScale(xs,-sdiff);
+ long scaledX = longMultiplyPowerTen(xs, raise);
+ if (scaledX != INFLATED) {
+ return add(scaledX, ys, scale2);
+ } else {
+ BigInteger bigsum = bigMultiplyPowerTen(xs,raise).add(ys);
+ return ((xs^ys)>=0) ? // same sign test
+ new BigDecimal(bigsum, INFLATED, scale2, 0)
+ : valueOf(bigsum, scale2, 0);
+ }
+ } else {
+ int raise = checkScale(ys,sdiff);
+ long scaledY = longMultiplyPowerTen(ys, raise);
+ if (scaledY != INFLATED) {
+ return add(xs, scaledY, scale1);
+ } else {
+ BigInteger bigsum = bigMultiplyPowerTen(ys,raise).add(xs);
+ return ((xs^ys)>=0) ?
+ new BigDecimal(bigsum, INFLATED, scale1, 0)
+ : valueOf(bigsum, scale1, 0);
+ }
+ }
+ }
+
+ private static BigDecimal add(final long xs, int scale1, BigInteger snd, int scale2) {
+ int rscale = scale1;
+ long sdiff = (long)rscale - scale2;
+ boolean sameSigns = (Long.signum(xs) == snd.signum);
+ BigInteger sum;
+ if (sdiff < 0) {
+ int raise = checkScale(xs,-sdiff);
+ rscale = scale2;
+ long scaledX = longMultiplyPowerTen(xs, raise);
+ if (scaledX == INFLATED) {
+ sum = snd.add(bigMultiplyPowerTen(xs,raise));
+ } else {
+ sum = snd.add(scaledX);
+ }
+ } else { //if (sdiff > 0) {
+ int raise = checkScale(snd,sdiff);
+ snd = bigMultiplyPowerTen(snd,raise);
+ sum = snd.add(xs);
+ }
+ return (sameSigns) ?
+ new BigDecimal(sum, INFLATED, rscale, 0) :
+ valueOf(sum, rscale, 0);
+ }
+
+ private static BigDecimal add(BigInteger fst, int scale1, BigInteger snd, int scale2) {
+ int rscale = scale1;
+ long sdiff = (long)rscale - scale2;
+ if (sdiff != 0) {
+ if (sdiff < 0) {
+ int raise = checkScale(fst,-sdiff);
+ rscale = scale2;
+ fst = bigMultiplyPowerTen(fst,raise);
+ } else {
+ int raise = checkScale(snd,sdiff);
+ snd = bigMultiplyPowerTen(snd,raise);
+ }
+ }
+ BigInteger sum = fst.add(snd);
+ return (fst.signum == snd.signum) ?
+ new BigDecimal(sum, INFLATED, rscale, 0) :
+ valueOf(sum, rscale, 0);
+ }
+
+ private static BigInteger bigMultiplyPowerTen(long value, int n) {
+ if (n <= 0)
+ return BigInteger.valueOf(value);
+ return bigTenToThe(n).multiply(value);
+ }
+
+ private static BigInteger bigMultiplyPowerTen(BigInteger value, int n) {
+ if (n <= 0)
+ return value;
+ if(n<LONG_TEN_POWERS_TABLE.length) {
+ return value.multiply(LONG_TEN_POWERS_TABLE[n]);
+ }
+ return value.multiply(bigTenToThe(n));
+ }
+
+ /**
+ * Returns a {@code BigDecimal} whose value is {@code (xs /
+ * ys)}, with rounding according to the context settings.
+ *
+ * Fast path - used only when (xscale <= yscale && yscale < 18
+ * && mc.presision<18) {
+ */
+ private static BigDecimal divideSmallFastPath(final long xs, int xscale,
+ final long ys, int yscale,
+ long preferredScale, MathContext mc) {
+ int mcp = mc.precision;
+ int roundingMode = mc.roundingMode.oldMode;
+
+ assert (xscale <= yscale) && (yscale < 18) && (mcp < 18);
+ int xraise = yscale - xscale; // xraise >=0
+ long scaledX = (xraise==0) ? xs :
+ longMultiplyPowerTen(xs, xraise); // can't overflow here!
+ BigDecimal quotient;
+
+ int cmp = longCompareMagnitude(scaledX, ys);
+ if(cmp > 0) { // satisfy constraint (b)
+ yscale -= 1; // [that is, divisor *= 10]
+ int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
+ if (checkScaleNonZero((long) mcp + yscale) > xscale) {
+ // assert newScale >= xscale
+ int raise = checkScaleNonZero((long) mcp + yscale - xscale);
+ long scaledXs;
+ if ((scaledXs = longMultiplyPowerTen(xs, raise)) == INFLATED) {
+ quotient = null;
+ if((mcp-1) >=0 && (mcp-1)<LONG_TEN_POWERS_TABLE.length) {
+ quotient = multiplyDivideAndRound(LONG_TEN_POWERS_TABLE[mcp-1], scaledX, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
+ }
+ if(quotient==null) {
+ BigInteger rb = bigMultiplyPowerTen(scaledX,mcp-1);
+ quotient = divideAndRound(rb, ys,
+ scl, roundingMode, checkScaleNonZero(preferredScale));
+ }
+ } else {
+ quotient = divideAndRound(scaledXs, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
+ }
+ } else {
+ int newScale = checkScaleNonZero((long) xscale - mcp);
+ // assert newScale >= yscale
+ if (newScale == yscale) { // easy case
+ quotient = divideAndRound(xs, ys, scl, roundingMode,checkScaleNonZero(preferredScale));
+ } else {
+ int raise = checkScaleNonZero((long) newScale - yscale);
+ long scaledYs;
+ if ((scaledYs = longMultiplyPowerTen(ys, raise)) == INFLATED) {
+ BigInteger rb = bigMultiplyPowerTen(ys,raise);
+ quotient = divideAndRound(BigInteger.valueOf(xs),
+ rb, scl, roundingMode,checkScaleNonZero(preferredScale));
+ } else {
+ quotient = divideAndRound(xs, scaledYs, scl, roundingMode,checkScaleNonZero(preferredScale));
+ }
+ }
+ }
+ } else {
+ // abs(scaledX) <= abs(ys)
+ // result is "scaledX * 10^msp / ys"
+ int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
+ if(cmp==0) {
+ // abs(scaleX)== abs(ys) => result will be scaled 10^mcp + correct sign
+ quotient = roundedTenPower(((scaledX < 0) == (ys < 0)) ? 1 : -1, mcp, scl, checkScaleNonZero(preferredScale));
+ } else {
+ // abs(scaledX) < abs(ys)
+ long scaledXs;
+ if ((scaledXs = longMultiplyPowerTen(scaledX, mcp)) == INFLATED) {
+ quotient = null;
+ if(mcp<LONG_TEN_POWERS_TABLE.length) {
+ quotient = multiplyDivideAndRound(LONG_TEN_POWERS_TABLE[mcp], scaledX, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
+ }
+ if(quotient==null) {
+ BigInteger rb = bigMultiplyPowerTen(scaledX,mcp);
+ quotient = divideAndRound(rb, ys,
+ scl, roundingMode, checkScaleNonZero(preferredScale));
+ }
+ } else {
+ quotient = divideAndRound(scaledXs, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
+ }
+ }
+ }
+ // doRound, here, only affects 1000000000 case.
+ return doRound(quotient,mc);
+ }
+
+ /**
+ * Returns a {@code BigDecimal} whose value is {@code (xs /
+ * ys)}, with rounding according to the context settings.
+ */
+ private static BigDecimal divide(final long xs, int xscale, final long ys, int yscale, long preferredScale, MathContext mc) {
+ int mcp = mc.precision;
+ if(xscale <= yscale && yscale < 18 && mcp<18) {
+ return divideSmallFastPath(xs, xscale, ys, yscale, preferredScale, mc);
+ }
+ if (compareMagnitudeNormalized(xs, xscale, ys, yscale) > 0) {// satisfy constraint (b)
+ yscale -= 1; // [that is, divisor *= 10]
+ }
+ int roundingMode = mc.roundingMode.oldMode;
+ // In order to find out whether the divide generates the exact result,
+ // we avoid calling the above divide method. 'quotient' holds the
+ // return BigDecimal object whose scale will be set to 'scl'.
+ int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
+ BigDecimal quotient;
+ if (checkScaleNonZero((long) mcp + yscale) > xscale) {
+ int raise = checkScaleNonZero((long) mcp + yscale - xscale);
+ long scaledXs;
+ if ((scaledXs = longMultiplyPowerTen(xs, raise)) == INFLATED) {
+ BigInteger rb = bigMultiplyPowerTen(xs,raise);
+ quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
+ } else {
+ quotient = divideAndRound(scaledXs, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
+ }
+ } else {
+ int newScale = checkScaleNonZero((long) xscale - mcp);
+ // assert newScale >= yscale
+ if (newScale == yscale) { // easy case
+ quotient = divideAndRound(xs, ys, scl, roundingMode,checkScaleNonZero(preferredScale));
+ } else {
+ int raise = checkScaleNonZero((long) newScale - yscale);
+ long scaledYs;
+ if ((scaledYs = longMultiplyPowerTen(ys, raise)) == INFLATED) {
+ BigInteger rb = bigMultiplyPowerTen(ys,raise);
+ quotient = divideAndRound(BigInteger.valueOf(xs),
+ rb, scl, roundingMode,checkScaleNonZero(preferredScale));
+ } else {
+ quotient = divideAndRound(xs, scaledYs, scl, roundingMode,checkScaleNonZero(preferredScale));
+ }
+ }
+ }
+ // doRound, here, only affects 1000000000 case.
+ return doRound(quotient,mc);
+ }
+
+ /**
+ * Returns a {@code BigDecimal} whose value is {@code (xs /
+ * ys)}, with rounding according to the context settings.
+ */
+ private static BigDecimal divide(BigInteger xs, int xscale, long ys, int yscale, long preferredScale, MathContext mc) {
+ // Normalize dividend & divisor so that both fall into [0.1, 0.999...]
+ if ((-compareMagnitudeNormalized(ys, yscale, xs, xscale)) > 0) {// satisfy constraint (b)
+ yscale -= 1; // [that is, divisor *= 10]
+ }
+ int mcp = mc.precision;
+ int roundingMode = mc.roundingMode.oldMode;
+
+ // In order to find out whether the divide generates the exact result,
+ // we avoid calling the above divide method. 'quotient' holds the
+ // return BigDecimal object whose scale will be set to 'scl'.
+ BigDecimal quotient;
+ int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
+ if (checkScaleNonZero((long) mcp + yscale) > xscale) {
+ int raise = checkScaleNonZero((long) mcp + yscale - xscale);
+ BigInteger rb = bigMultiplyPowerTen(xs,raise);
+ quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
+ } else {
+ int newScale = checkScaleNonZero((long) xscale - mcp);
+ // assert newScale >= yscale
+ if (newScale == yscale) { // easy case
+ quotient = divideAndRound(xs, ys, scl, roundingMode,checkScaleNonZero(preferredScale));
+ } else {
+ int raise = checkScaleNonZero((long) newScale - yscale);
+ long scaledYs;
+ if ((scaledYs = longMultiplyPowerTen(ys, raise)) == INFLATED) {
+ BigInteger rb = bigMultiplyPowerTen(ys,raise);
+ quotient = divideAndRound(xs, rb, scl, roundingMode,checkScaleNonZero(preferredScale));
+ } else {
+ quotient = divideAndRound(xs, scaledYs, scl, roundingMode,checkScaleNonZero(preferredScale));
+ }
+ }
+ }
+ // doRound, here, only affects 1000000000 case.
+ return doRound(quotient, mc);
+ }
+
+ /**
+ * Returns a {@code BigDecimal} whose value is {@code (xs /
+ * ys)}, with rounding according to the context settings.
+ */
+ private static BigDecimal divide(long xs, int xscale, BigInteger ys, int yscale, long preferredScale, MathContext mc) {
+ // Normalize dividend & divisor so that both fall into [0.1, 0.999...]
+ if (compareMagnitudeNormalized(xs, xscale, ys, yscale) > 0) {// satisfy constraint (b)
+ yscale -= 1; // [that is, divisor *= 10]
+ }
+ int mcp = mc.precision;
+ int roundingMode = mc.roundingMode.oldMode;
+
+ // In order to find out whether the divide generates the exact result,
+ // we avoid calling the above divide method. 'quotient' holds the
+ // return BigDecimal object whose scale will be set to 'scl'.
+ BigDecimal quotient;
+ int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
+ if (checkScaleNonZero((long) mcp + yscale) > xscale) {
+ int raise = checkScaleNonZero((long) mcp + yscale - xscale);
+ BigInteger rb = bigMultiplyPowerTen(xs,raise);
+ quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
+ } else {
+ int newScale = checkScaleNonZero((long) xscale - mcp);
+ int raise = checkScaleNonZero((long) newScale - yscale);
+ BigInteger rb = bigMultiplyPowerTen(ys,raise);
+ quotient = divideAndRound(BigInteger.valueOf(xs), rb, scl, roundingMode,checkScaleNonZero(preferredScale));
+ }
+ // doRound, here, only affects 1000000000 case.
+ return doRound(quotient, mc);
+ }
+
+ /**
+ * Returns a {@code BigDecimal} whose value is {@code (xs /
+ * ys)}, with rounding according to the context settings.
+ */
+ private static BigDecimal divide(BigInteger xs, int xscale, BigInteger ys, int yscale, long preferredScale, MathContext mc) {
+ // Normalize dividend & divisor so that both fall into [0.1, 0.999...]
+ if (compareMagnitudeNormalized(xs, xscale, ys, yscale) > 0) {// satisfy constraint (b)
+ yscale -= 1; // [that is, divisor *= 10]
+ }
+ int mcp = mc.precision;
+ int roundingMode = mc.roundingMode.oldMode;
+
+ // In order to find out whether the divide generates the exact result,
+ // we avoid calling the above divide method. 'quotient' holds the
+ // return BigDecimal object whose scale will be set to 'scl'.
+ BigDecimal quotient;
+ int scl = checkScaleNonZero(preferredScale + yscale - xscale + mcp);
+ if (checkScaleNonZero((long) mcp + yscale) > xscale) {
+ int raise = checkScaleNonZero((long) mcp + yscale - xscale);
+ BigInteger rb = bigMultiplyPowerTen(xs,raise);
+ quotient = divideAndRound(rb, ys, scl, roundingMode, checkScaleNonZero(preferredScale));
+ } else {
+ int newScale = checkScaleNonZero((long) xscale - mcp);
+ int raise = checkScaleNonZero((long) newScale - yscale);
+ BigInteger rb = bigMultiplyPowerTen(ys,raise);
+ quotient = divideAndRound(xs, rb, scl, roundingMode,checkScaleNonZero(preferredScale));
+ }
+ // doRound, here, only affects 1000000000 case.
+ return doRound(quotient, mc);
+ }
+
+ /*
+ * performs divideAndRound for (dividend0*dividend1, divisor)
+ * returns null if quotient can't fit into long value;
+ */
+ private static BigDecimal multiplyDivideAndRound(long dividend0, long dividend1, long divisor, int scale, int roundingMode,
+ int preferredScale) {
+ int qsign = Long.signum(dividend0)*Long.signum(dividend1)*Long.signum(divisor);
+ dividend0 = Math.abs(dividend0);
+ dividend1 = Math.abs(dividend1);
+ divisor = Math.abs(divisor);
+ // multiply dividend0 * dividend1
+ long d0_hi = dividend0 >>> 32;
+ long d0_lo = dividend0 & LONG_MASK;
+ long d1_hi = dividend1 >>> 32;
+ long d1_lo = dividend1 & LONG_MASK;
+ long product = d0_lo * d1_lo;
+ long d0 = product & LONG_MASK;
+ long d1 = product >>> 32;
+ product = d0_hi * d1_lo + d1;
+ d1 = product & LONG_MASK;
+ long d2 = product >>> 32;
+ product = d0_lo * d1_hi + d1;
+ d1 = product & LONG_MASK;
+ d2 += product >>> 32;
+ long d3 = d2>>>32;
+ d2 &= LONG_MASK;
+ product = d0_hi*d1_hi + d2;
+ d2 = product & LONG_MASK;
+ d3 = ((product>>>32) + d3) & LONG_MASK;
+ final long dividendHi = make64(d3,d2);
+ final long dividendLo = make64(d1,d0);
+ // divide
+ return divideAndRound128(dividendHi, dividendLo, divisor, qsign, scale, roundingMode, preferredScale);
+ }
+
+ private static final long DIV_NUM_BASE = (1L<<32); // Number base (32 bits).
+
+ /*
+ * divideAndRound 128-bit value by long divisor.
+ * returns null if quotient can't fit into long value;
+ * Specialized version of Knuth's division
+ */
+ private static BigDecimal divideAndRound128(final long dividendHi, final long dividendLo, long divisor, int sign,
+ int scale, int roundingMode, int preferredScale) {
+ if (dividendHi >= divisor) {
+ return null;
+ }
+ final int shift = Long.numberOfLeadingZeros(divisor);
+ divisor <<= shift;
+
+ final long v1 = divisor >>> 32;
+ final long v0 = divisor & LONG_MASK;
+
+ long q1, q0;
+ long r_tmp;
+
+ long tmp = dividendLo << shift;
+ long u1 = tmp >>> 32;
+ long u0 = tmp & LONG_MASK;
+
+ tmp = (dividendHi << shift) | (dividendLo >>> 64 - shift);
+ long u2 = tmp & LONG_MASK;
+ tmp = divWord(tmp,v1);
+ q1 = tmp & LONG_MASK;
+ r_tmp = tmp >>> 32;
+ while(q1 >= DIV_NUM_BASE || unsignedLongCompare(q1*v0, make64(r_tmp, u1))) {
+ q1--;
+ r_tmp += v1;
+ if (r_tmp >= DIV_NUM_BASE)
+ break;
+ }
+ tmp = mulsub(u2,u1,v1,v0,q1);
+ u1 = tmp & LONG_MASK;
+ tmp = divWord(tmp,v1);
+ q0 = tmp & LONG_MASK;
+ r_tmp = tmp >>> 32;
+ while(q0 >= DIV_NUM_BASE || unsignedLongCompare(q0*v0,make64(r_tmp,u0))) {
+ q0--;
+ r_tmp += v1;
+ if (r_tmp >= DIV_NUM_BASE)
+ break;
+ }
+ if((int)q1 < 0) {
+ // result (which is positive and unsigned here)
+ // can't fit into long due to sign bit is used for value
+ MutableBigInteger mq = new MutableBigInteger(new int[]{(int)q1, (int)q0});
+ if (roundingMode == ROUND_DOWN && scale == preferredScale) {
+ return mq.toBigDecimal(sign, scale);
+ }
+ long r = mulsub(u1, u0, v1, v0, q0) >>> shift;
+ if (r != 0) {
+ if(needIncrement(divisor >>> shift, roundingMode, sign, mq, r)){
+ mq.add(MutableBigInteger.ONE);
+ }
+ return mq.toBigDecimal(sign, scale);
+ } else {
+ if (preferredScale != scale) {
+ BigInteger intVal = mq.toBigInteger(sign);
+ return createAndStripZerosToMatchScale(intVal,scale, preferredScale);
+ } else {
+ return mq.toBigDecimal(sign, scale);
+ }
+ }
+ }
+ long q = make64(q1,q0);
+ q*=sign;
+ if (roundingMode == ROUND_DOWN && scale == preferredScale)
+ return valueOf(q, scale);
+ long r = mulsub(u1, u0, v1, v0, q0) >>> shift;
+ if (r != 0) {
+ boolean increment = needIncrement(divisor >>> shift, roundingMode, sign, q, r);
+ return valueOf((increment ? q + sign : q), scale);
+ } else {
+ if (preferredScale != scale) {
+ return createAndStripZerosToMatchScale(q, scale, preferredScale);
+ } else {
+ return valueOf(q, scale);
+ }
+ }
+ }
+
+ /*
+ * calculate divideAndRound for ldividend*10^raise / divisor
+ * when abs(dividend)==abs(divisor);
+ */
+ private static BigDecimal roundedTenPower(int qsign, int raise, int scale, int preferredScale) {
+ if (scale > preferredScale) {
+ int diff = scale - preferredScale;
+ if(diff < raise) {
+ return scaledTenPow(raise - diff, qsign, preferredScale);
+ } else {
+ return valueOf(qsign,scale-raise);
+ }
+ } else {
+ return scaledTenPow(raise, qsign, scale);
+ }
+ }
+
+ static BigDecimal scaledTenPow(int n, int sign, int scale) {
+ if (n < LONG_TEN_POWERS_TABLE.length)
+ return valueOf(sign*LONG_TEN_POWERS_TABLE[n],scale);
+ else {
+ BigInteger unscaledVal = bigTenToThe(n);
+ if(sign==-1) {
+ unscaledVal = unscaledVal.negate();
+ }
+ return new BigDecimal(unscaledVal, INFLATED, scale, n+1);
+ }
+ }
+
+ private static long divWord(long n, long dLong) {
+ long r;
+ long q;
+ if (dLong == 1) {
+ q = (int)n;
+ return (q & LONG_MASK);
+ }
+ // Approximate the quotient and remainder
+ q = (n >>> 1) / (dLong >>> 1);
+ r = n - q*dLong;
+
+ // Correct the approximation
+ while (r < 0) {
+ r += dLong;
+ q--;
+ }
+ while (r >= dLong) {
+ r -= dLong;
+ q++;
+ }
+ // n - q*dlong == r && 0 <= r <dLong, hence we're done.
+ return (r << 32) | (q & LONG_MASK);
+ }
+
+ private static long make64(long hi, long lo) {
+ return hi<<32 | lo;
+ }
+
+ private static long mulsub(long u1, long u0, final long v1, final long v0, long q0) {
+ long tmp = u0 - q0*v0;
+ return make64(u1 + (tmp>>>32) - q0*v1,tmp & LONG_MASK);
+ }
+
+ private static boolean unsignedLongCompare(long one, long two) {
+ return (one+Long.MIN_VALUE) > (two+Long.MIN_VALUE);
+ }
+
+ private static boolean unsignedLongCompareEq(long one, long two) {
+ return (one+Long.MIN_VALUE) >= (two+Long.MIN_VALUE);
+ }
+
+
+ // Compare Normalize dividend & divisor so that both fall into [0.1, 0.999...]
+ private static int compareMagnitudeNormalized(long xs, int xscale, long ys, int yscale) {
+ // assert xs!=0 && ys!=0
+ int sdiff = xscale - yscale;
+ if (sdiff != 0) {
+ if (sdiff < 0) {
+ xs = longMultiplyPowerTen(xs, -sdiff);
+ } else { // sdiff > 0
+ ys = longMultiplyPowerTen(ys, sdiff);
+ }
+ }
+ if (xs != INFLATED)
+ return (ys != INFLATED) ? longCompareMagnitude(xs, ys) : -1;
+ else
+ return 1;
+ }
+
+ // Compare Normalize dividend & divisor so that both fall into [0.1, 0.999...]
+ private static int compareMagnitudeNormalized(long xs, int xscale, BigInteger ys, int yscale) {
+ // assert "ys can't be represented as long"
+ if (xs == 0)
+ return -1;
+ int sdiff = xscale - yscale;
+ if (sdiff < 0) {
+ if (longMultiplyPowerTen(xs, -sdiff) == INFLATED ) {
+ return bigMultiplyPowerTen(xs, -sdiff).compareMagnitude(ys);
+ }
+ }
+ return -1;
+ }
+
+ // Compare Normalize dividend & divisor so that both fall into [0.1, 0.999...]
+ private static int compareMagnitudeNormalized(BigInteger xs, int xscale, BigInteger ys, int yscale) {
+ int sdiff = xscale - yscale;
+ if (sdiff < 0) {
+ return bigMultiplyPowerTen(xs, -sdiff).compareMagnitude(ys);
+ } else { // sdiff >= 0
+ return xs.compareMagnitude(bigMultiplyPowerTen(ys, sdiff));
+ }
+ }
+
+ private static long multiply(long x, long y){
+ long product = x * y;
+ long ax = Math.abs(x);
+ long ay = Math.abs(y);
+ if (((ax | ay) >>> 31 == 0) || (y == 0) || (product / y == x)){
+ return product;
+ }
+ return INFLATED;
+ }
+
+ private static BigDecimal multiply(long x, long y, int scale) {
+ long product = multiply(x, y);
+ if(product!=INFLATED) {
+ return valueOf(product,scale);
+ }
+ return new BigDecimal(BigInteger.valueOf(x).multiply(y),INFLATED,scale,0);
+ }
+
+ private static BigDecimal multiply(long x, BigInteger y, int scale) {
+ if(x==0) {
+ return zeroValueOf(scale);
+ }
+ return new BigDecimal(y.multiply(x),INFLATED,scale,0);
+ }
+
+ private static BigDecimal multiply(BigInteger x, BigInteger y, int scale) {
+ return new BigDecimal(x.multiply(y),INFLATED,scale,0);
+ }
+
+ /**
+ * Multiplies two long values and rounds according {@code MathContext}
+ */
+ private static BigDecimal multiplyAndRound(long x, long y, int scale, MathContext mc) {
+ long product = multiply(x, y);
+ if(product!=INFLATED) {
+ return doRound(product, scale, mc);
+ }
+ // attempt to do it in 128 bits
+ int rsign = 1;
+ if(x < 0) {
+ x = -x;
+ rsign = -1;
+ }
+ if(y < 0) {
+ y = -y;
+ rsign *= -1;
+ }
+ // multiply dividend0 * dividend1
+ long m0_hi = x >>> 32;
+ long m0_lo = x & LONG_MASK;
+ long m1_hi = y >>> 32;
+ long m1_lo = y & LONG_MASK;
+ product = m0_lo * m1_lo;
+ long m0 = product & LONG_MASK;
+ long m1 = product >>> 32;
+ product = m0_hi * m1_lo + m1;
+ m1 = product & LONG_MASK;
+ long m2 = product >>> 32;
+ product = m0_lo * m1_hi + m1;
+ m1 = product & LONG_MASK;
+ m2 += product >>> 32;
+ long m3 = m2>>>32;
+ m2 &= LONG_MASK;
+ product = m0_hi*m1_hi + m2;
+ m2 = product & LONG_MASK;
+ m3 = ((product>>>32) + m3) & LONG_MASK;
+ final long mHi = make64(m3,m2);
+ final long mLo = make64(m1,m0);
+ BigDecimal res = doRound128(mHi, mLo, rsign, scale, mc);
+ if(res!=null) {
+ return res;
+ }
+ res = new BigDecimal(BigInteger.valueOf(x).multiply(y*rsign), INFLATED, scale, 0);
+ return doRound(res,mc);
+ }
+
+ private static BigDecimal multiplyAndRound(long x, BigInteger y, int scale, MathContext mc) {
+ if(x==0) {
+ return zeroValueOf(scale);
+ }
+ return doRound(y.multiply(x), scale, mc);
+ }
+
+ private static BigDecimal multiplyAndRound(BigInteger x, BigInteger y, int scale, MathContext mc) {
+ return doRound(x.multiply(y), scale, mc);
+ }
+
+ /**
+ * rounds 128-bit value according {@code MathContext}
+ * returns null if result can't be repsented as compact BigDecimal.
+ */
+ private static BigDecimal doRound128(long hi, long lo, int sign, int scale, MathContext mc) {
+ int mcp = mc.precision;
+ int drop;
+ BigDecimal res = null;
+ if(((drop = precision(hi, lo) - mcp) > 0)&&(drop<LONG_TEN_POWERS_TABLE.length)) {
+ scale = checkScaleNonZero((long)scale - drop);
+ res = divideAndRound128(hi, lo, LONG_TEN_POWERS_TABLE[drop], sign, scale, mc.roundingMode.oldMode, scale);
+ }
+ if(res!=null) {
+ return doRound(res,mc);
+ }
+ return null;
+ }
+
+ private static final long[][] LONGLONG_TEN_POWERS_TABLE = {
+ { 0L, 0x8AC7230489E80000L }, //10^19
+ { 0x5L, 0x6bc75e2d63100000L }, //10^20
+ { 0x36L, 0x35c9adc5dea00000L }, //10^21
+ { 0x21eL, 0x19e0c9bab2400000L }, //10^22
+ { 0x152dL, 0x02c7e14af6800000L }, //10^23
+ { 0xd3c2L, 0x1bcecceda1000000L }, //10^24
+ { 0x84595L, 0x161401484a000000L }, //10^25
+ { 0x52b7d2L, 0xdcc80cd2e4000000L }, //10^26
+ { 0x33b2e3cL, 0x9fd0803ce8000000L }, //10^27
+ { 0x204fce5eL, 0x3e25026110000000L }, //10^28
+ { 0x1431e0faeL, 0x6d7217caa0000000L }, //10^29
+ { 0xc9f2c9cd0L, 0x4674edea40000000L }, //10^30
+ { 0x7e37be2022L, 0xc0914b2680000000L }, //10^31
+ { 0x4ee2d6d415bL, 0x85acef8100000000L }, //10^32
+ { 0x314dc6448d93L, 0x38c15b0a00000000L }, //10^33
+ { 0x1ed09bead87c0L, 0x378d8e6400000000L }, //10^34
+ { 0x13426172c74d82L, 0x2b878fe800000000L }, //10^35
+ { 0xc097ce7bc90715L, 0xb34b9f1000000000L }, //10^36
+ { 0x785ee10d5da46d9L, 0x00f436a000000000L }, //10^37
+ { 0x4b3b4ca85a86c47aL, 0x098a224000000000L }, //10^38
+ };
+
+ /*
+ * returns precision of 128-bit value
+ */
+ private static int precision(long hi, long lo){
+ if(hi==0) {
+ if(lo>=0) {
+ return longDigitLength(lo);
+ }
+ return (unsignedLongCompareEq(lo, LONGLONG_TEN_POWERS_TABLE[0][1])) ? 20 : 19;
+ // 0x8AC7230489E80000L = unsigned 2^19
+ }
+ int r = ((128 - Long.numberOfLeadingZeros(hi) + 1) * 1233) >>> 12;
+ int idx = r-19;
+ return (idx >= LONGLONG_TEN_POWERS_TABLE.length || longLongCompareMagnitude(hi, lo,
+ LONGLONG_TEN_POWERS_TABLE[idx][0], LONGLONG_TEN_POWERS_TABLE[idx][1])) ? r : r + 1;
+ }
+
+ /*
+ * returns true if 128 bit number <hi0,lo0> is less then <hi1,lo1>
+ * hi0 & hi1 should be non-negative
+ */
+ private static boolean longLongCompareMagnitude(long hi0, long lo0, long hi1, long lo1) {
+ if(hi0!=hi1) {
+ return hi0<hi1;
+ }
+ return (lo0+Long.MIN_VALUE) <(lo1+Long.MIN_VALUE);
+ }
+
+ private static BigDecimal divide(long dividend, int dividendScale, long divisor, int divisorScale, int scale, int roundingMode) {
+ if (checkScale(dividend,(long)scale + divisorScale) > dividendScale) {
+ int newScale = scale + divisorScale;
+ int raise = newScale - dividendScale;
+ if(raise<LONG_TEN_POWERS_TABLE.length) {
+ long xs = dividend;
+ if ((xs = longMultiplyPowerTen(xs, raise)) != INFLATED) {
+ return divideAndRound(xs, divisor, scale, roundingMode, scale);
+ }
+ BigDecimal q = multiplyDivideAndRound(LONG_TEN_POWERS_TABLE[raise], dividend, divisor, scale, roundingMode, scale);
+ if(q!=null) {
+ return q;
+ }
+ }
+ BigInteger scaledDividend = bigMultiplyPowerTen(dividend, raise);
+ return divideAndRound(scaledDividend, divisor, scale, roundingMode, scale);
+ } else {
+ int newScale = checkScale(divisor,(long)dividendScale - scale);
+ int raise = newScale - divisorScale;
+ if(raise<LONG_TEN_POWERS_TABLE.length) {
+ long ys = divisor;
+ if ((ys = longMultiplyPowerTen(ys, raise)) != INFLATED) {
+ return divideAndRound(dividend, ys, scale, roundingMode, scale);
+ }
+ }
+ BigInteger scaledDivisor = bigMultiplyPowerTen(divisor, raise);
+ return divideAndRound(BigInteger.valueOf(dividend), scaledDivisor, scale, roundingMode, scale);
+ }
+ }
+
+ private static BigDecimal divide(BigInteger dividend, int dividendScale, long divisor, int divisorScale, int scale, int roundingMode) {
+ if (checkScale(dividend,(long)scale + divisorScale) > dividendScale) {
+ int newScale = scale + divisorScale;
+ int raise = newScale - dividendScale;
+ BigInteger scaledDividend = bigMultiplyPowerTen(dividend, raise);
+ return divideAndRound(scaledDividend, divisor, scale, roundingMode, scale);
+ } else {
+ int newScale = checkScale(divisor,(long)dividendScale - scale);
+ int raise = newScale - divisorScale;
+ if(raise<LONG_TEN_POWERS_TABLE.length) {
+ long ys = divisor;
+ if ((ys = longMultiplyPowerTen(ys, raise)) != INFLATED) {
+ return divideAndRound(dividend, ys, scale, roundingMode, scale);
+ }
+ }
+ BigInteger scaledDivisor = bigMultiplyPowerTen(divisor, raise);
+ return divideAndRound(dividend, scaledDivisor, scale, roundingMode, scale);
+ }
+ }
+
+ private static BigDecimal divide(long dividend, int dividendScale, BigInteger divisor, int divisorScale, int scale, int roundingMode) {
+ if (checkScale(dividend,(long)scale + divisorScale) > dividendScale) {
+ int newScale = scale + divisorScale;
+ int raise = newScale - dividendScale;
+ BigInteger scaledDividend = bigMultiplyPowerTen(dividend, raise);
+ return divideAndRound(scaledDividend, divisor, scale, roundingMode, scale);
+ } else {
+ int newScale = checkScale(divisor,(long)dividendScale - scale);
+ int raise = newScale - divisorScale;
+ BigInteger scaledDivisor = bigMultiplyPowerTen(divisor, raise);
+ return divideAndRound(BigInteger.valueOf(dividend), scaledDivisor, scale, roundingMode, scale);
+ }
+ }
+
+ private static BigDecimal divide(BigInteger dividend, int dividendScale, BigInteger divisor, int divisorScale, int scale, int roundingMode) {
+ if (checkScale(dividend,(long)scale + divisorScale) > dividendScale) {
+ int newScale = scale + divisorScale;
+ int raise = newScale - dividendScale;
+ BigInteger scaledDividend = bigMultiplyPowerTen(dividend, raise);
+ return divideAndRound(scaledDividend, divisor, scale, roundingMode, scale);
+ } else {
+ int newScale = checkScale(divisor,(long)dividendScale - scale);
+ int raise = newScale - divisorScale;
+ BigInteger scaledDivisor = bigMultiplyPowerTen(divisor, raise);
+ return divideAndRound(dividend, scaledDivisor, scale, roundingMode, scale);
+ }
+ }
+
}
--- a/jdk/src/share/classes/java/math/BigInteger.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/math/BigInteger.java Mon Sep 12 16:59:34 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
import java.util.Random;
import java.io.*;
+import java.util.Arrays;
/**
* Immutable arbitrary-precision integers. All operations behave as if
@@ -353,27 +354,17 @@
mag = trustedStripLeadingZeroInts(magnitude);
}
- // Constructs a new BigInteger using a char array with radix=10
- BigInteger(char[] val) {
+ /*
+ * Constructs a new BigInteger using a char array with radix=10.
+ * Sign is precalculated outside and not allowed in the val.
+ */
+ BigInteger(char[] val, int sign, int len) {
int cursor = 0, numDigits;
- int len = val.length;
-
- // Check for leading minus sign
- int sign = 1;
- if (val[0] == '-') {
- if (len == 1)
- throw new NumberFormatException("Zero length BigInteger");
- sign = -1;
- cursor = 1;
- } else if (val[0] == '+') {
- if (len == 1)
- throw new NumberFormatException("Zero length BigInteger");
- cursor = 1;
- }
// Skip leading zeros and compute number of digits in magnitude
- while (cursor < len && Character.digit(val[cursor], 10) == 0)
+ while (cursor < len && Character.digit(val[cursor], 10) == 0) {
cursor++;
+ }
if (cursor == len) {
signum = 0;
mag = ZERO.mag;
@@ -382,7 +373,6 @@
numDigits = len - cursor;
signum = sign;
-
// Pre-allocate array of expected size
int numWords;
if (len < 10) {
@@ -1058,6 +1048,73 @@
}
/**
+ * Package private methods used by BigDecimal code to add a BigInteger
+ * with a long. Assumes val is not equal to INFLATED.
+ */
+ BigInteger add(long val) {
+ if (val == 0)
+ return this;
+ if (signum == 0)
+ return valueOf(val);
+ if (Long.signum(val) == signum)
+ return new BigInteger(add(mag, Math.abs(val)), signum);
+ int cmp = compareMagnitude(val);
+ if (cmp == 0)
+ return ZERO;
+ int[] resultMag = (cmp > 0 ? subtract(mag, Math.abs(val)) : subtract(Math.abs(val), mag));
+ resultMag = trustedStripLeadingZeroInts(resultMag);
+ return new BigInteger(resultMag, cmp == signum ? 1 : -1);
+ }
+
+ /**
+ * Adds the contents of the int array x and long value val. This
+ * method allocates a new int array to hold the answer and returns
+ * a reference to that array. Assumes x.length > 0 and val is
+ * non-negative
+ */
+ private static int[] add(int[] x, long val) {
+ int[] y;
+ long sum = 0;
+ int xIndex = x.length;
+ int[] result;
+ int highWord = (int)(val >>> 32);
+ if (highWord==0) {
+ result = new int[xIndex];
+ sum = (x[--xIndex] & LONG_MASK) + val;
+ result[xIndex] = (int)sum;
+ } else {
+ if (xIndex == 1) {
+ result = new int[2];
+ sum = val + (x[0] & LONG_MASK);
+ result[1] = (int)sum;
+ result[0] = (int)(sum >>> 32);
+ return result;
+ } else {
+ result = new int[xIndex];
+ sum = (x[--xIndex] & LONG_MASK) + (val & LONG_MASK);
+ result[xIndex] = (int)sum;
+ sum = (x[--xIndex] & LONG_MASK) + (highWord & LONG_MASK) + (sum >>> 32);
+ result[xIndex] = (int)sum;
+ }
+ }
+ // Copy remainder of longer number while carry propagation is required
+ boolean carry = (sum >>> 32 != 0);
+ while (xIndex > 0 && carry)
+ carry = ((result[--xIndex] = x[xIndex] + 1) == 0);
+ // Copy remainder of longer number
+ while (xIndex > 0)
+ result[--xIndex] = x[xIndex];
+ // Grow result if necessary
+ if (carry) {
+ int bigger[] = new int[result.length + 1];
+ System.arraycopy(result, 0, bigger, 1, result.length);
+ bigger[0] = 0x01;
+ return bigger;
+ }
+ return result;
+ }
+
+ /**
* Adds the contents of the int arrays x and y. This method allocates
* a new int array to hold the answer and returns a reference to that
* array.
@@ -1074,14 +1131,17 @@
int yIndex = y.length;
int result[] = new int[xIndex];
long sum = 0;
-
- // Add common parts of both numbers
- while(yIndex > 0) {
- sum = (x[--xIndex] & LONG_MASK) +
- (y[--yIndex] & LONG_MASK) + (sum >>> 32);
+ if(yIndex==1) {
+ sum = (x[--xIndex] & LONG_MASK) + (y[0] & LONG_MASK) ;
result[xIndex] = (int)sum;
+ } else {
+ // Add common parts of both numbers
+ while(yIndex > 0) {
+ sum = (x[--xIndex] & LONG_MASK) +
+ (y[--yIndex] & LONG_MASK) + (sum >>> 32);
+ result[xIndex] = (int)sum;
+ }
}
-
// Copy remainder of longer number while carry propagation is required
boolean carry = (sum >>> 32 != 0);
while (xIndex > 0 && carry)
@@ -1101,6 +1161,71 @@
return result;
}
+ private static int[] subtract(long val, int[] little) {
+ int highWord = (int)(val >>> 32);
+ if (highWord==0) {
+ int result[] = new int[1];
+ result[0] = (int)(val - (little[0] & LONG_MASK));
+ return result;
+ } else {
+ int result[] = new int[2];
+ if(little.length==1) {
+ long difference = ((int)val & LONG_MASK) - (little[0] & LONG_MASK);
+ result[1] = (int)difference;
+ // Subtract remainder of longer number while borrow propagates
+ boolean borrow = (difference >> 32 != 0);
+ if(borrow) {
+ result[0] = highWord - 1;
+ } else { // Copy remainder of longer number
+ result[0] = highWord;
+ }
+ return result;
+ } else { // little.length==2
+ long difference = ((int)val & LONG_MASK) - (little[1] & LONG_MASK);
+ result[1] = (int)difference;
+ difference = (highWord & LONG_MASK) - (little[0] & LONG_MASK) + (difference >> 32);
+ result[0] = (int)difference;
+ return result;
+ }
+ }
+ }
+
+ /**
+ * Subtracts the contents of the second argument (val) from the
+ * first (big). The first int array (big) must represent a larger number
+ * than the second. This method allocates the space necessary to hold the
+ * answer.
+ * assumes val >= 0
+ */
+ private static int[] subtract(int[] big, long val) {
+ int highWord = (int)(val >>> 32);
+ int bigIndex = big.length;
+ int result[] = new int[bigIndex];
+ long difference = 0;
+
+ if (highWord==0) {
+ difference = (big[--bigIndex] & LONG_MASK) - val;
+ result[bigIndex] = (int)difference;
+ } else {
+ difference = (big[--bigIndex] & LONG_MASK) - (val & LONG_MASK);
+ result[bigIndex] = (int)difference;
+ difference = (big[--bigIndex] & LONG_MASK) - (highWord & LONG_MASK) + (difference >> 32);
+ result[bigIndex] = (int)difference;
+ }
+
+
+ // Subtract remainder of longer number while borrow propagates
+ boolean borrow = (difference >> 32 != 0);
+ while (bigIndex > 0 && borrow)
+ borrow = ((result[--bigIndex] = big[bigIndex] - 1) == -1);
+
+ // Copy remainder of longer number
+ while (bigIndex > 0)
+ result[--bigIndex] = big[bigIndex];
+
+ return result;
+ }
+
/**
* Returns a BigInteger whose value is {@code (this - val)}.
*
@@ -1165,11 +1290,39 @@
public BigInteger multiply(BigInteger val) {
if (val.signum == 0 || signum == 0)
return ZERO;
-
+ int resultSign = signum == val.signum ? 1 : -1;
+ if (val.mag.length == 1) {
+ return multiplyByInt(mag,val.mag[0], resultSign);
+ }
+ if(mag.length == 1) {
+ return multiplyByInt(val.mag,mag[0], resultSign);
+ }
int[] result = multiplyToLen(mag, mag.length,
val.mag, val.mag.length, null);
result = trustedStripLeadingZeroInts(result);
- return new BigInteger(result, signum == val.signum ? 1 : -1);
+ return new BigInteger(result, resultSign);
+ }
+
+ private static BigInteger multiplyByInt(int[] x, int y, int sign) {
+ if(Integer.bitCount(y)==1) {
+ return new BigInteger(shiftLeft(x,Integer.numberOfTrailingZeros(y)), sign);
+ }
+ int xlen = x.length;
+ int[] rmag = new int[xlen + 1];
+ long carry = 0;
+ long yl = y & LONG_MASK;
+ int rstart = rmag.length - 1;
+ for (int i = xlen - 1; i >= 0; i--) {
+ long product = (x[i] & LONG_MASK) * yl + carry;
+ rmag[rstart--] = (int)product;
+ carry = product >>> 32;
+ }
+ if (carry == 0L) {
+ rmag = java.util.Arrays.copyOfRange(rmag, 1, rmag.length);
+ } else {
+ rmag[rstart] = (int)carry;
+ }
+ return new BigInteger(rmag, sign);
}
/**
@@ -1339,8 +1492,8 @@
a = new MutableBigInteger(this.mag),
b = new MutableBigInteger(val.mag);
- a.divide(b, q);
- return q.toBigInteger(this.signum == val.signum ? 1 : -1);
+ a.divide(b, q, false);
+ return q.toBigInteger(this.signum * val.signum);
}
/**
@@ -1460,14 +1613,12 @@
} else { // Array must be resized
if (nBits <= (32-bitsInHighWord)) {
int result[] = new int[nInts+len];
- for (int i=0; i<len; i++)
- result[i] = a[i];
+ System.arraycopy(a, 0, result, 0, len);
primitiveLeftShift(result, result.length, nBits);
return result;
} else {
int result[] = new int[nInts+len+1];
- for (int i=0; i<len; i++)
- result[i] = a[i];
+ System.arraycopy(a, 0, result, 0, len);
primitiveRightShift(result, result.length, 32 - nBits);
return result;
}
@@ -1755,9 +1906,7 @@
b = montReduce(b, mod, modLen, inv);
// Set t to high half of b
- int[] t = new int[modLen];
- for(int i=0; i<modLen; i++)
- t[i] = b[i];
+ int[] t = Arrays.copyOf(b, modLen);
// Fill in the table with odd powers of the base
for (int i=1; i<tblmask; i++) {
@@ -1854,14 +2003,11 @@
// Convert result out of Montgomery form and return
int[] t2 = new int[2*modLen];
- for(int i=0; i<modLen; i++)
- t2[i+modLen] = b[i];
+ System.arraycopy(b, 0, t2, modLen, modLen);
b = montReduce(t2, mod, modLen, inv);
- t2 = new int[modLen];
- for(int i=0; i<modLen; i++)
- t2[i] = b[i];
+ t2 = Arrays.copyOf(b, modLen);
return new BigInteger(1, t2);
}
@@ -2002,8 +2148,7 @@
// Copy remaining ints of mag
int numInts = (p + 31) >>> 5;
int[] mag = new int[numInts];
- for (int i=0; i<numInts; i++)
- mag[i] = this.mag[i + (this.mag.length - numInts)];
+ System.arraycopy(this.mag, (this.mag.length - numInts), mag, 0, numInts);
// Mask out any excess bits
int excessBits = (numInts << 5) - p;
@@ -2069,7 +2214,12 @@
return shiftRight(-n);
}
}
-
+ int[] newMag = shiftLeft(mag, n);
+
+ return new BigInteger(newMag, signum);
+ }
+
+ private static int[] shiftLeft(int[] mag, int n) {
int nInts = n >>> 5;
int nBits = n & 0x1f;
int magLen = mag.length;
@@ -2077,8 +2227,7 @@
if (nBits == 0) {
newMag = new int[magLen + nInts];
- for (int i=0; i<magLen; i++)
- newMag[i] = mag[i];
+ System.arraycopy(mag, 0, newMag, 0, magLen);
} else {
int i = 0;
int nBits2 = 32 - nBits;
@@ -2094,8 +2243,7 @@
newMag[i++] = mag[j++] << nBits | mag[j] >>> nBits2;
newMag[i] = mag[j] << nBits;
}
-
- return new BigInteger(newMag, signum);
+ return newMag;
}
/**
@@ -2132,9 +2280,7 @@
if (nBits == 0) {
int newMagLen = magLen - nInts;
- newMag = new int[newMagLen];
- for (int i=0; i<newMagLen; i++)
- newMag[i] = mag[i];
+ newMag = Arrays.copyOf(mag, newMagLen);
} else {
int i = 0;
int highBits = mag[0] >>> nBits;
@@ -2405,7 +2551,7 @@
if (signum < 0) {
// Check if magnitude is a power of two
boolean pow2 = (Integer.bitCount(mag[0]) == 1);
- for(int i=1; i< len && pow2; i++)
+ for (int i=1; i< len && pow2; i++)
pow2 = (mag[i] == 0);
n = (pow2 ? magBitLength -1 : magBitLength);
@@ -2530,6 +2676,49 @@
}
/**
+ * Version of compareMagnitude that compares magnitude with long value.
+ * val can't be Long.MIN_VALUE.
+ */
+ final int compareMagnitude(long val) {
+ assert val != Long.MIN_VALUE;
+ int[] m1 = mag;
+ int len = m1.length;
+ if(len > 2) {
+ return 1;
+ }
+ if (val < 0) {
+ val = -val;
+ }
+ int highWord = (int)(val >>> 32);
+ if (highWord==0) {
+ if (len < 1)
+ return -1;
+ if (len > 1)
+ return 1;
+ int a = m1[0];
+ int b = (int)val;
+ if (a != b) {
+ return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1;
+ }
+ return 0;
+ } else {
+ if (len < 2)
+ return -1;
+ int a = m1[0];
+ int b = highWord;
+ if (a != b) {
+ return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1;
+ }
+ a = m1[1];
+ b = (int)val;
+ if (a != b) {
+ return ((a & LONG_MASK) < (b & LONG_MASK))? -1 : 1;
+ }
+ return 0;
+ }
+ }
+
+ /**
* Compares this BigInteger with the specified Object for equality.
*
* @param x Object to which this BigInteger is to be compared.
@@ -3114,25 +3303,35 @@
}
// Commit final fields via Unsafe
- unsafe.putIntVolatile(this, signumOffset, sign);
+ UnsafeHolder.putSign(this, sign);
// Calculate mag field from magnitude and discard magnitude
- unsafe.putObjectVolatile(this, magOffset,
- stripLeadingZeroBytes(magnitude));
+ UnsafeHolder.putMag(this, stripLeadingZeroBytes(magnitude));
}
// Support for resetting final fields while deserializing
- private static final sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
- private static final long signumOffset;
- private static final long magOffset;
- static {
- try {
- signumOffset = unsafe.objectFieldOffset
- (BigInteger.class.getDeclaredField("signum"));
- magOffset = unsafe.objectFieldOffset
- (BigInteger.class.getDeclaredField("mag"));
- } catch (Exception ex) {
- throw new Error(ex);
+ private static class UnsafeHolder {
+ private static final sun.misc.Unsafe unsafe;
+ private static final long signumOffset;
+ private static final long magOffset;
+ static {
+ try {
+ unsafe = sun.misc.Unsafe.getUnsafe();
+ signumOffset = unsafe.objectFieldOffset
+ (BigInteger.class.getDeclaredField("signum"));
+ magOffset = unsafe.objectFieldOffset
+ (BigInteger.class.getDeclaredField("mag"));
+ } catch (Exception ex) {
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ static void putSign(BigInteger bi, int sign) {
+ unsafe.putIntVolatile(bi, signumOffset, sign);
+ }
+
+ static void putMag(BigInteger bi, int[] magnitude) {
+ unsafe.putObjectVolatile(bi, magOffset, magnitude);
}
}
--- a/jdk/src/share/classes/java/math/MutableBigInteger.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/math/MutableBigInteger.java Mon Sep 12 16:59:34 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -160,7 +160,7 @@
*/
BigDecimal toBigDecimal(int sign, int scale) {
if (intLen == 0 || sign == 0)
- return BigDecimal.valueOf(0, scale);
+ return BigDecimal.zeroValueOf(scale);
int[] mag = getMagnitudeArray();
int len = mag.length;
int d = mag[0];
@@ -171,7 +171,28 @@
long v = (len == 2) ?
((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) :
d & LONG_MASK;
- return new BigDecimal(null, sign == -1 ? -v : v, scale, 0);
+ return BigDecimal.valueOf(sign == -1 ? -v : v, scale);
+ }
+
+ /**
+ * This is for internal use in converting from a MutableBigInteger
+ * object into a long value given a specified sign.
+ * returns INFLATED if value is not fit into long
+ */
+ long toCompactValue(int sign) {
+ if (intLen == 0 || sign == 0)
+ return 0L;
+ int[] mag = getMagnitudeArray();
+ int len = mag.length;
+ int d = mag[0];
+ // If this MutableBigInteger can not be fitted into long, we need to
+ // make a BigInteger object for the resultant BigDecimal object.
+ if (len > 2 || (d < 0 && len == 2))
+ return INFLATED;
+ long v = (len == 2) ?
+ ((mag[1] & LONG_MASK) | (d & LONG_MASK) << 32) :
+ d & LONG_MASK;
+ return sign == -1 ? -v : v;
}
/**
@@ -544,6 +565,24 @@
}
/**
+ * The method is the same as mulsun, except the fact that q array is not
+ * updated, the only result of the method is borrow flag.
+ */
+ private int mulsubBorrow(int[] q, int[] a, int x, int len, int offset) {
+ long xLong = x & LONG_MASK;
+ long carry = 0;
+ offset += len;
+ for (int j=len-1; j >= 0; j--) {
+ long product = (a[j] & LONG_MASK) * xLong + carry;
+ long difference = q[offset--] - product;
+ carry = (product >>> 32)
+ + (((difference & LONG_MASK) >
+ (((~(int)product) & LONG_MASK))) ? 1:0);
+ }
+ return (int)carry;
+ }
+
+ /**
* Right shift this MutableBigInteger n bits, where n is
* less than 32.
* Assumes that intLen > 0, n > 0 for speed
@@ -842,20 +881,20 @@
rem = (int) (remLong - (quotient.value[0] * divisorLong));
remLong = rem & LONG_MASK;
}
-
int xlen = intLen;
- int[] qWord = new int[2];
while (--xlen > 0) {
- long dividendEstimate = (remLong<<32) |
- (value[offset + intLen - xlen] & LONG_MASK);
+ long dividendEstimate = (remLong << 32) |
+ (value[offset + intLen - xlen] & LONG_MASK);
+ int q;
if (dividendEstimate >= 0) {
- qWord[0] = (int) (dividendEstimate / divisorLong);
- qWord[1] = (int) (dividendEstimate - qWord[0] * divisorLong);
+ q = (int) (dividendEstimate / divisorLong);
+ rem = (int) (dividendEstimate - q * divisorLong);
} else {
- divWord(qWord, dividendEstimate, divisor);
+ long tmp = divWord(dividendEstimate, divisor);
+ q = (int) (tmp & LONG_MASK);
+ rem = (int) (tmp >>> 32);
}
- quotient.value[intLen - xlen] = qWord[0];
- rem = qWord[1];
+ quotient.value[intLen - xlen] = q;
remLong = rem & LONG_MASK;
}
@@ -879,40 +918,45 @@
*
*/
MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient) {
+ return divide(b,quotient,true);
+ }
+
+ MutableBigInteger divide(MutableBigInteger b, MutableBigInteger quotient, boolean needReminder) {
if (b.intLen == 0)
throw new ArithmeticException("BigInteger divide by zero");
// Dividend is zero
if (intLen == 0) {
quotient.intLen = quotient.offset;
- return new MutableBigInteger();
+ return needReminder ? new MutableBigInteger() : null;
}
int cmp = compare(b);
// Dividend less than divisor
if (cmp < 0) {
quotient.intLen = quotient.offset = 0;
- return new MutableBigInteger(this);
+ return needReminder ? new MutableBigInteger(this) : null;
}
// Dividend equal to divisor
if (cmp == 0) {
quotient.value[0] = quotient.intLen = 1;
quotient.offset = 0;
- return new MutableBigInteger();
+ return needReminder ? new MutableBigInteger() : null;
}
quotient.clear();
// Special case one word divisor
if (b.intLen == 1) {
int r = divideOneWord(b.value[b.offset], quotient);
- if (r == 0)
- return new MutableBigInteger();
- return new MutableBigInteger(r);
+ if(needReminder) {
+ if (r == 0)
+ return new MutableBigInteger();
+ return new MutableBigInteger(r);
+ } else {
+ return null;
+ }
}
-
- // Copy divisor value to protect divisor
- int[] div = Arrays.copyOfRange(b.value, b.offset, b.offset + b.intLen);
- return divideMagnitude(div, quotient);
+ return divideMagnitude(b, quotient, needReminder);
}
/**
@@ -940,30 +984,72 @@
if (d == 0)
return divideOneWord((int)v, quotient) & LONG_MASK;
else {
- int[] div = new int[]{ d, (int)(v & LONG_MASK) };
- return divideMagnitude(div, quotient).toLong();
+ return divideLongMagnitude(v, quotient).toLong();
}
}
+ private static void copyAndShift(int[] src, int srcFrom, int srcLen, int[] dst, int dstFrom, int shift) {
+ int n2 = 32 - shift;
+ int c=src[srcFrom];
+ for (int i=0; i < srcLen-1; i++) {
+ int b = c;
+ c = src[++srcFrom];
+ dst[dstFrom+i] = (b << shift) | (c >>> n2);
+ }
+ dst[dstFrom+srcLen-1] = c << shift;
+ }
+
/**
- * Divide this MutableBigInteger by the divisor represented by its magnitude
- * array. The quotient will be placed into the provided quotient object &
+ * Divide this MutableBigInteger by the divisor.
+ * The quotient will be placed into the provided quotient object &
* the remainder object is returned.
*/
- private MutableBigInteger divideMagnitude(int[] divisor,
- MutableBigInteger quotient) {
-
- // Remainder starts as dividend with space for a leading zero
- MutableBigInteger rem = new MutableBigInteger(new int[intLen + 1]);
- System.arraycopy(value, offset, rem.value, 1, intLen);
- rem.intLen = intLen;
- rem.offset = 1;
+ private MutableBigInteger divideMagnitude(MutableBigInteger div,
+ MutableBigInteger quotient,
+ boolean needReminder ) {
+ // assert div.intLen > 1
+ // D1 normalize the divisor
+ int shift = Integer.numberOfLeadingZeros(div.value[div.offset]);
+ // Copy divisor value to protect divisor
+ final int dlen = div.intLen;
+ int[] divisor;
+ MutableBigInteger rem; // Remainder starts as dividend with space for a leading zero
+ if (shift > 0) {
+ divisor = new int[dlen];
+ copyAndShift(div.value,div.offset,dlen,divisor,0,shift);
+ if(Integer.numberOfLeadingZeros(value[offset])>=shift) {
+ int[] remarr = new int[intLen + 1];
+ rem = new MutableBigInteger(remarr);
+ rem.intLen = intLen;
+ rem.offset = 1;
+ copyAndShift(value,offset,intLen,remarr,1,shift);
+ } else {
+ int[] remarr = new int[intLen + 2];
+ rem = new MutableBigInteger(remarr);
+ rem.intLen = intLen+1;
+ rem.offset = 1;
+ int rFrom = offset;
+ int c=0;
+ int n2 = 32 - shift;
+ for (int i=1; i < intLen+1; i++,rFrom++) {
+ int b = c;
+ c = value[rFrom];
+ remarr[i] = (b << shift) | (c >>> n2);
+ }
+ remarr[intLen+1] = c << shift;
+ }
+ } else {
+ divisor = Arrays.copyOfRange(div.value, div.offset, div.offset + div.intLen);
+ rem = new MutableBigInteger(new int[intLen + 1]);
+ System.arraycopy(value, offset, rem.value, 1, intLen);
+ rem.intLen = intLen;
+ rem.offset = 1;
+ }
int nlen = rem.intLen;
// Set the quotient size
- int dlen = divisor.length;
- int limit = nlen - dlen + 1;
+ final int limit = nlen - dlen + 1;
if (quotient.value.length < limit) {
quotient.value = new int[limit];
quotient.offset = 0;
@@ -971,14 +1057,6 @@
quotient.intLen = limit;
int[] q = quotient.value;
- // D1 normalize the divisor
- int shift = Integer.numberOfLeadingZeros(divisor[0]);
- if (shift > 0) {
- // First shift will not grow array
- BigInteger.primitiveLeftShift(divisor, dlen, shift);
- // But this one might
- rem.leftShift(shift);
- }
// Must insert leading 0 in rem if its length did not change
if (rem.intLen == nlen) {
@@ -990,10 +1068,9 @@
int dh = divisor[0];
long dhLong = dh & LONG_MASK;
int dl = divisor[1];
- int[] qWord = new int[2];
// D2 Initialize j
- for(int j=0; j<limit; j++) {
+ for(int j=0; j<limit-1; j++) {
// D3 Calculate qhat
// estimate qhat
int qhat = 0;
@@ -1013,9 +1090,9 @@
qhat = (int) (nChunk / dhLong);
qrem = (int) (nChunk - (qhat * dhLong));
} else {
- divWord(qWord, nChunk, dh);
- qhat = qWord[0];
- qrem = qWord[1];
+ long tmp = divWord(nChunk, dh);
+ qhat = (int) (tmp & LONG_MASK);
+ qrem = (int) (tmp >>> 32);
}
}
@@ -1053,6 +1130,181 @@
// Store the quotient digit
q[j] = qhat;
} // D7 loop on j
+ // D3 Calculate qhat
+ // estimate qhat
+ int qhat = 0;
+ int qrem = 0;
+ boolean skipCorrection = false;
+ int nh = rem.value[limit - 1 + rem.offset];
+ int nh2 = nh + 0x80000000;
+ int nm = rem.value[limit + rem.offset];
+
+ if (nh == dh) {
+ qhat = ~0;
+ qrem = nh + nm;
+ skipCorrection = qrem + 0x80000000 < nh2;
+ } else {
+ long nChunk = (((long) nh) << 32) | (nm & LONG_MASK);
+ if (nChunk >= 0) {
+ qhat = (int) (nChunk / dhLong);
+ qrem = (int) (nChunk - (qhat * dhLong));
+ } else {
+ long tmp = divWord(nChunk, dh);
+ qhat = (int) (tmp & LONG_MASK);
+ qrem = (int) (tmp >>> 32);
+ }
+ }
+ if (qhat != 0) {
+ if (!skipCorrection) { // Correct qhat
+ long nl = rem.value[limit + 1 + rem.offset] & LONG_MASK;
+ long rs = ((qrem & LONG_MASK) << 32) | nl;
+ long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK);
+
+ if (unsignedLongCompare(estProduct, rs)) {
+ qhat--;
+ qrem = (int) ((qrem & LONG_MASK) + dhLong);
+ if ((qrem & LONG_MASK) >= dhLong) {
+ estProduct -= (dl & LONG_MASK);
+ rs = ((qrem & LONG_MASK) << 32) | nl;
+ if (unsignedLongCompare(estProduct, rs))
+ qhat--;
+ }
+ }
+ }
+
+
+ // D4 Multiply and subtract
+ int borrow;
+ rem.value[limit - 1 + rem.offset] = 0;
+ if(needReminder)
+ borrow = mulsub(rem.value, divisor, qhat, dlen, limit - 1 + rem.offset);
+ else
+ borrow = mulsubBorrow(rem.value, divisor, qhat, dlen, limit - 1 + rem.offset);
+
+ // D5 Test remainder
+ if (borrow + 0x80000000 > nh2) {
+ // D6 Add back
+ if(needReminder)
+ divadd(divisor, rem.value, limit - 1 + 1 + rem.offset);
+ qhat--;
+ }
+
+ // Store the quotient digit
+ q[(limit - 1)] = qhat;
+ }
+
+
+ if(needReminder) {
+ // D8 Unnormalize
+ if (shift > 0)
+ rem.rightShift(shift);
+ rem.normalize();
+ }
+ quotient.normalize();
+ return needReminder ? rem : null;
+ }
+
+ /**
+ * Divide this MutableBigInteger by the divisor represented by positive long
+ * value. The quotient will be placed into the provided quotient object &
+ * the remainder object is returned.
+ */
+ private MutableBigInteger divideLongMagnitude(long ldivisor, MutableBigInteger quotient) {
+ // Remainder starts as dividend with space for a leading zero
+ MutableBigInteger rem = new MutableBigInteger(new int[intLen + 1]);
+ System.arraycopy(value, offset, rem.value, 1, intLen);
+ rem.intLen = intLen;
+ rem.offset = 1;
+
+ int nlen = rem.intLen;
+
+ int limit = nlen - 2 + 1;
+ if (quotient.value.length < limit) {
+ quotient.value = new int[limit];
+ quotient.offset = 0;
+ }
+ quotient.intLen = limit;
+ int[] q = quotient.value;
+
+ // D1 normalize the divisor
+ int shift = Long.numberOfLeadingZeros(ldivisor);
+ if (shift > 0) {
+ ldivisor<<=shift;
+ rem.leftShift(shift);
+ }
+
+ // Must insert leading 0 in rem if its length did not change
+ if (rem.intLen == nlen) {
+ rem.offset = 0;
+ rem.value[0] = 0;
+ rem.intLen++;
+ }
+
+ int dh = (int)(ldivisor >>> 32);
+ long dhLong = dh & LONG_MASK;
+ int dl = (int)(ldivisor & LONG_MASK);
+
+ // D2 Initialize j
+ for (int j = 0; j < limit; j++) {
+ // D3 Calculate qhat
+ // estimate qhat
+ int qhat = 0;
+ int qrem = 0;
+ boolean skipCorrection = false;
+ int nh = rem.value[j + rem.offset];
+ int nh2 = nh + 0x80000000;
+ int nm = rem.value[j + 1 + rem.offset];
+
+ if (nh == dh) {
+ qhat = ~0;
+ qrem = nh + nm;
+ skipCorrection = qrem + 0x80000000 < nh2;
+ } else {
+ long nChunk = (((long) nh) << 32) | (nm & LONG_MASK);
+ if (nChunk >= 0) {
+ qhat = (int) (nChunk / dhLong);
+ qrem = (int) (nChunk - (qhat * dhLong));
+ } else {
+ long tmp = divWord(nChunk, dh);
+ qhat =(int)(tmp & LONG_MASK);
+ qrem = (int)(tmp>>>32);
+ }
+ }
+
+ if (qhat == 0)
+ continue;
+
+ if (!skipCorrection) { // Correct qhat
+ long nl = rem.value[j + 2 + rem.offset] & LONG_MASK;
+ long rs = ((qrem & LONG_MASK) << 32) | nl;
+ long estProduct = (dl & LONG_MASK) * (qhat & LONG_MASK);
+
+ if (unsignedLongCompare(estProduct, rs)) {
+ qhat--;
+ qrem = (int) ((qrem & LONG_MASK) + dhLong);
+ if ((qrem & LONG_MASK) >= dhLong) {
+ estProduct -= (dl & LONG_MASK);
+ rs = ((qrem & LONG_MASK) << 32) | nl;
+ if (unsignedLongCompare(estProduct, rs))
+ qhat--;
+ }
+ }
+ }
+
+ // D4 Multiply and subtract
+ rem.value[j + rem.offset] = 0;
+ int borrow = mulsubLong(rem.value, dh, dl, qhat, j + rem.offset);
+
+ // D5 Test remainder
+ if (borrow + 0x80000000 > nh2) {
+ // D6 Add back
+ divaddLong(dh,dl, rem.value, j + 1 + rem.offset);
+ qhat--;
+ }
+
+ // Store the quotient digit
+ q[j] = qhat;
+ } // D7 loop on j
// D8 Unnormalize
if (shift > 0)
@@ -1064,6 +1316,46 @@
}
/**
+ * A primitive used for division by long.
+ * Specialized version of the method divadd.
+ * dh is a high part of the divisor, dl is a low part
+ */
+ private int divaddLong(int dh, int dl, int[] result, int offset) {
+ long carry = 0;
+
+ long sum = (dl & LONG_MASK) + (result[1+offset] & LONG_MASK);
+ result[1+offset] = (int)sum;
+
+ sum = (dh & LONG_MASK) + (result[offset] & LONG_MASK) + carry;
+ result[offset] = (int)sum;
+ carry = sum >>> 32;
+ return (int)carry;
+ }
+
+ /**
+ * This method is used for division by long.
+ * Specialized version of the method sulsub.
+ * dh is a high part of the divisor, dl is a low part
+ */
+ private int mulsubLong(int[] q, int dh, int dl, int x, int offset) {
+ long xLong = x & LONG_MASK;
+ offset += 2;
+ long product = (dl & LONG_MASK) * xLong;
+ long difference = q[offset] - product;
+ q[offset--] = (int)difference;
+ long carry = (product >>> 32)
+ + (((difference & LONG_MASK) >
+ (((~(int)product) & LONG_MASK))) ? 1:0);
+ product = (dh & LONG_MASK) * xLong + carry;
+ difference = q[offset] - product;
+ q[offset--] = (int)difference;
+ carry = (product >>> 32)
+ + (((difference & LONG_MASK) >
+ (((~(int)product) & LONG_MASK))) ? 1:0);
+ return (int)carry;
+ }
+
+ /**
* Compare two longs as if they were unsigned.
* Returns true iff one is bigger than two.
*/
@@ -1075,19 +1367,22 @@
* This method divides a long quantity by an int to estimate
* qhat for two multi precision numbers. It is used when
* the signed value of n is less than zero.
+ * Returns long value where high 32 bits contain reminder value and
+ * low 32 bits contain quotient value.
*/
- private void divWord(int[] result, long n, int d) {
+ static long divWord(long n, int d) {
long dLong = d & LONG_MASK;
-
+ long r;
+ long q;
if (dLong == 1) {
- result[0] = (int)n;
- result[1] = 0;
- return;
+ q = (int)n;
+ r = 0;
+ return (r << 32) | (q & LONG_MASK);
}
// Approximate the quotient and remainder
- long q = (n >>> 1) / (dLong >>> 1);
- long r = n - q*dLong;
+ q = (n >>> 1) / (dLong >>> 1);
+ r = n - q*dLong;
// Correct the approximation
while (r < 0) {
@@ -1098,10 +1393,8 @@
r -= dLong;
q++;
}
-
// n - q*dlong == r && 0 <= r <dLong, hence we're done.
- result[0] = (int)q;
- result[1] = (int)r;
+ return (r << 32) | (q & LONG_MASK);
}
/**
@@ -1473,5 +1766,4 @@
mod.subtract(t1);
return mod;
}
-
}
--- a/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java Mon Sep 12 16:59:34 2011 -0700
@@ -457,10 +457,10 @@
}
/*
- * If connection has been reset then return 0 to indicate
- * there are no buffered bytes.
+ * If connection has been reset or shut down for input, then return 0
+ * to indicate there are no buffered bytes.
*/
- if (isConnectionReset()) {
+ if (isConnectionReset() || shut_rd) {
return 0;
}
--- a/jdk/src/share/classes/java/net/DatagramSocket.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/net/DatagramSocket.java Mon Sep 12 16:59:34 2011 -0700
@@ -174,9 +174,7 @@
* @see SecurityManager#checkListen
*/
public DatagramSocket() throws SocketException {
- // create a datagram socket.
- createImpl();
- bind(new InetSocketAddress(0));
+ this(new InetSocketAddress(0));
}
/**
@@ -221,7 +219,12 @@
// create a datagram socket.
createImpl();
if (bindaddr != null) {
- bind(bindaddr);
+ try {
+ bind(bindaddr);
+ } finally {
+ if (!isBound())
+ close();
+ }
}
}
--- a/jdk/src/share/classes/java/net/MulticastSocket.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/net/MulticastSocket.java Mon Sep 12 16:59:34 2011 -0700
@@ -162,7 +162,12 @@
setReuseAddress(true);
if (bindaddr != null) {
- bind(bindaddr);
+ try {
+ bind(bindaddr);
+ } finally {
+ if (!isBound())
+ close();
+ }
}
}
--- a/jdk/src/share/classes/java/net/Socket.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/net/Socket.java Mon Sep 12 16:59:34 2011 -0700
@@ -28,7 +28,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
-import java.io.InterruptedIOException;
import java.nio.channels.SocketChannel;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
@@ -421,10 +420,13 @@
createImpl(stream);
if (localAddr != null)
bind(localAddr);
- if (address != null)
- connect(address);
- } catch (IOException e) {
- close();
+ connect(address);
+ } catch (IOException | IllegalArgumentException | SecurityException e) {
+ try {
+ close();
+ } catch (IOException ce) {
+ e.addSuppressed(ce);
+ }
throw e;
}
}
@@ -1436,8 +1438,9 @@
* Any data sent to the input stream side of the socket is acknowledged
* and then silently discarded.
* <p>
- * If you read from a socket input stream after invoking
- * shutdownInput() on the socket, the stream will return EOF.
+ * If you read from a socket input stream after invoking this method on the
+ * socket, the stream's {@code available} method will return 0, and its
+ * {@code read} methods will return {@code -1} (end of stream).
*
* @exception IOException if an I/O error occurs when shutting down this
* socket.
--- a/jdk/src/share/classes/java/net/SocketImpl.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/net/SocketImpl.java Mon Sep 12 16:59:34 2011 -0700
@@ -181,8 +181,9 @@
* Any data sent to this socket is acknowledged and then
* silently discarded.
*
- * If you read from a socket input stream after invoking
- * shutdownInput() on the socket, the stream will return EOF.
+ * If you read from a socket input stream after invoking this method on the
+ * socket, the stream's {@code available} method will return 0, and its
+ * {@code read} methods will return {@code -1} (end of stream).
*
* @exception IOException if an I/O error occurs when shutting down this
* socket.
--- a/jdk/src/share/classes/java/net/URI.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/net/URI.java Mon Sep 12 16:59:34 2011 -0700
@@ -1711,6 +1711,8 @@
i++;
continue;
}
+ if (d != '%')
+ return false;
i++;
if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
return false;
--- a/jdk/src/share/classes/java/rmi/dgc/VMID.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/rmi/dgc/VMID.java Mon Sep 12 16:59:34 2011 -0700
@@ -170,7 +170,7 @@
/* can't happen, but be deterministic anyway. */
addrHash = new byte[0];
} catch (NoSuchAlgorithmException complain) {
- throw new InternalError(complain.toString());
+ throw new InternalError(complain.toString(), complain);
}
return addrHash;
}
--- a/jdk/src/share/classes/java/security/cert/CollectionCertStoreParameters.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/security/cert/CollectionCertStoreParameters.java Mon Sep 12 16:59:34 2011 -0700
@@ -122,7 +122,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
/* Cannot happen */
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
--- a/jdk/src/share/classes/java/security/cert/LDAPCertStoreParameters.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/security/cert/LDAPCertStoreParameters.java Mon Sep 12 16:59:34 2011 -0700
@@ -128,7 +128,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
/* Cannot happen */
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
--- a/jdk/src/share/classes/java/security/cert/PKIXCertPathChecker.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/security/cert/PKIXCertPathChecker.java Mon Sep 12 16:59:34 2011 -0700
@@ -175,7 +175,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
/* Cannot happen */
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
}
--- a/jdk/src/share/classes/java/security/cert/PKIXCertPathValidatorResult.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/security/cert/PKIXCertPathValidatorResult.java Mon Sep 12 16:59:34 2011 -0700
@@ -136,7 +136,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
/* Cannot happen */
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
--- a/jdk/src/share/classes/java/security/cert/PKIXParameters.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/security/cert/PKIXParameters.java Mon Sep 12 16:59:34 2011 -0700
@@ -683,7 +683,7 @@
return copy;
} catch (CloneNotSupportedException e) {
/* Cannot happen */
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
--- a/jdk/src/share/classes/java/security/cert/X509CRLSelector.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/security/cert/X509CRLSelector.java Mon Sep 12 16:59:34 2011 -0700
@@ -708,7 +708,7 @@
return copy;
} catch (CloneNotSupportedException e) {
/* Cannot happen */
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
}
--- a/jdk/src/share/classes/java/security/cert/X509CertSelector.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/security/cert/X509CertSelector.java Mon Sep 12 16:59:34 2011 -0700
@@ -2615,7 +2615,7 @@
return copy;
} catch (CloneNotSupportedException e) {
/* Cannot happen */
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
}
--- a/jdk/src/share/classes/java/text/AttributedString.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/text/AttributedString.java Mon Sep 12 16:59:34 2011 -0700
@@ -794,7 +794,7 @@
return other;
}
catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/text/BreakDictionary.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/text/BreakDictionary.java Mon Sep 12 16:59:34 2011 -0700
@@ -154,7 +154,7 @@
);
}
catch (PrivilegedActionException e) {
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
byte[] buf = new byte[8];
--- a/jdk/src/share/classes/java/text/BreakIterator.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/text/BreakIterator.java Mon Sep 12 16:59:34 2011 -0700
@@ -254,7 +254,7 @@
return super.clone();
}
catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
@@ -617,7 +617,7 @@
}
}
catch (Exception e) {
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
--- a/jdk/src/share/classes/java/text/Collator.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/text/Collator.java Mon Sep 12 16:59:34 2011 -0700
@@ -461,7 +461,7 @@
try {
return (Collator)super.clone();
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/text/DateFormatSymbols.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/text/DateFormatSymbols.java Mon Sep 12 16:59:34 2011 -0700
@@ -597,7 +597,7 @@
copyMembers(this, other);
return other;
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/text/DecimalFormat.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/text/DecimalFormat.java Mon Sep 12 16:59:34 2011 -0700
@@ -1891,14 +1891,10 @@
* Standard override; no change in semantics.
*/
public Object clone() {
- try {
- DecimalFormat other = (DecimalFormat) super.clone();
- other.symbols = (DecimalFormatSymbols) symbols.clone();
- other.digitList = (DigitList) digitList.clone();
- return other;
- } catch (Exception e) {
- throw new InternalError();
- }
+ DecimalFormat other = (DecimalFormat) super.clone();
+ other.symbols = (DecimalFormatSymbols) symbols.clone();
+ other.digitList = (DigitList) digitList.clone();
+ return other;
}
/**
--- a/jdk/src/share/classes/java/text/DecimalFormatSymbols.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/text/DecimalFormatSymbols.java Mon Sep 12 16:59:34 2011 -0700
@@ -479,7 +479,7 @@
return (DecimalFormatSymbols)super.clone();
// other fields are bit-copied
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/text/DigitList.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/text/DigitList.java Mon Sep 12 16:59:34 2011 -0700
@@ -632,7 +632,7 @@
other.tempBuffer = null;
return other;
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/text/Format.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/text/Format.java Mon Sep 12 16:59:34 2011 -0700
@@ -258,7 +258,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// will never happen
- return null;
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/text/RuleBasedBreakIterator.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/text/RuleBasedBreakIterator.java Mon Sep 12 16:59:34 2011 -0700
@@ -453,7 +453,7 @@
);
}
catch (PrivilegedActionException e) {
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
int offset = 0;
--- a/jdk/src/share/classes/java/text/StringCharacterIterator.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/text/StringCharacterIterator.java Mon Sep 12 16:59:34 2011 -0700
@@ -272,7 +272,7 @@
return other;
}
catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/util/ArrayList.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/ArrayList.java Mon Sep 12 16:59:34 2011 -0700
@@ -307,7 +307,7 @@
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/util/BitSet.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/BitSet.java Mon Sep 12 16:59:34 2011 -0700
@@ -1092,7 +1092,7 @@
result.checkInvariants();
return result;
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/util/Calendar.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/Calendar.java Mon Sep 12 16:59:34 2011 -0700
@@ -2512,7 +2512,7 @@
}
catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/util/Currency.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/Currency.java Mon Sep 12 16:59:34 2011 -0700
@@ -221,9 +221,7 @@
otherCurrenciesNumericCode = readIntArray(dis, ocCount);
dis.close();
} catch (IOException e) {
- InternalError ie = new InternalError();
- ie.initCause(e);
- throw ie;
+ throw new InternalError(e);
}
// look for the properties file for overrides
--- a/jdk/src/share/classes/java/util/HashSet.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/HashSet.java Mon Sep 12 16:59:34 2011 -0700
@@ -253,7 +253,7 @@
newSet.map = (HashMap<E, Object>) map.clone();
return newSet;
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/util/Hashtable.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/Hashtable.java Mon Sep 12 16:59:34 2011 -0700
@@ -537,7 +537,7 @@
return t;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/util/IdentityHashMap.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/IdentityHashMap.java Mon Sep 12 16:59:34 2011 -0700
@@ -703,7 +703,7 @@
m.table = table.clone();
return m;
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/util/LinkedList.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/LinkedList.java Mon Sep 12 16:59:34 2011 -0700
@@ -994,7 +994,7 @@
try {
return (LinkedList<E>) super.clone();
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/util/Locale.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/Locale.java Mon Sep 12 16:59:34 2011 -0700
@@ -1859,7 +1859,7 @@
Locale that = (Locale)super.clone();
return that;
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/util/ResourceBundle.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/ResourceBundle.java Mon Sep 12 16:59:34 2011 -0700
@@ -614,7 +614,7 @@
return clone;
} catch (CloneNotSupportedException e) {
//this should never happen
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/util/TimeZone.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/TimeZone.java Mon Sep 12 16:59:34 2011 -0700
@@ -739,7 +739,7 @@
other.ID = ID;
return other;
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/util/TreeMap.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/TreeMap.java Mon Sep 12 16:59:34 2011 -0700
@@ -622,7 +622,7 @@
try {
clone = (TreeMap<K,V>) super.clone();
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
// Put clone into "virgin" state (except for comparator)
--- a/jdk/src/share/classes/java/util/TreeSet.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/TreeSet.java Mon Sep 12 16:59:34 2011 -0700
@@ -474,7 +474,7 @@
try {
clone = (TreeSet<E>) super.clone();
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
clone.m = new TreeMap<>(m);
--- a/jdk/src/share/classes/java/util/UUID.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/UUID.java Mon Sep 12 16:59:34 2011 -0700
@@ -165,7 +165,7 @@
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException nsae) {
- throw new InternalError("MD5 not supported");
+ throw new InternalError("MD5 not supported", nsae);
}
byte[] md5Bytes = md.digest(name);
md5Bytes[6] &= 0x0f; /* clear version */
--- a/jdk/src/share/classes/java/util/Vector.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/Vector.java Mon Sep 12 16:59:34 2011 -0700
@@ -673,7 +673,7 @@
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/java/util/zip/ZipEntry.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/java/util/zip/ZipEntry.java Mon Sep 12 16:59:34 2011 -0700
@@ -321,7 +321,7 @@
return e;
} catch (CloneNotSupportedException e) {
// This should never happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
}
--- a/jdk/src/share/classes/javax/management/openmbean/TabularDataSupport.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/javax/management/openmbean/TabularDataSupport.java Mon Sep 12 16:59:34 2011 -0700
@@ -671,7 +671,7 @@
return c;
}
catch (CloneNotSupportedException e) {
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
--- a/jdk/src/share/classes/javax/swing/text/ElementIterator.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/javax/swing/text/ElementIterator.java Mon Sep 12 16:59:34 2011 -0700
@@ -157,7 +157,7 @@
}
return it;
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/javax/swing/text/rtf/RTFReader.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/javax/swing/text/rtf/RTFReader.java Mon Sep 12 16:59:34 2011 -0700
@@ -528,7 +528,7 @@
try {
translationTable = (char[])getCharacterSet("ansi");
} catch (IOException e) {
- throw new InternalError("RTFReader: Unable to find character set resources (" + e + ")");
+ throw new InternalError("RTFReader: Unable to find character set resources (" + e + ")", e);
}
}
}
@@ -1614,7 +1614,7 @@
} catch (BadLocationException ble) {
/* This shouldn't be able to happen, of course */
/* TODO is InternalError the correct error to throw? */
- throw new InternalError(ble.getMessage());
+ throw new InternalError(ble.getMessage(), ble);
}
}
@@ -1628,7 +1628,7 @@
} catch (BadLocationException ble) {
/* This shouldn't be able to happen, of course */
/* TODO is InternalError the correct error to throw? */
- throw new InternalError(ble.getMessage());
+ throw new InternalError(ble.getMessage(), ble);
}
}
--- a/jdk/src/share/classes/sun/dc/DuctusRenderingEngine.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/dc/DuctusRenderingEngine.java Mon Sep 12 16:59:34 2011 -0700
@@ -158,7 +158,7 @@
feedConsumer(pi, consumer, normalize, 0.25f);
} catch (PathException e) {
throw new InternalError("Unable to Stroke shape ("+
- e.getMessage()+")");
+ e.getMessage()+")", e);
} finally {
while (consumer != null && consumer != sr) {
PathConsumer next = consumer.getConsumer();
@@ -763,7 +763,7 @@
consumer.endPath();
} catch (PathException e) {
throw new InternalError("Unable to Stroke shape ("+
- e.getMessage()+")");
+ e.getMessage()+")", e);
}
}
--- a/jdk/src/share/classes/sun/font/FontLineMetrics.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/font/FontLineMetrics.java Mon Sep 12 16:59:34 2011 -0700
@@ -113,7 +113,7 @@
return super.clone();
}
catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
}
--- a/jdk/src/share/classes/sun/font/GlyphLayout.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/font/GlyphLayout.java Mon Sep 12 16:59:34 2011 -0700
@@ -233,7 +233,7 @@
invdtx = dtx.createInverse();
}
catch (NoninvertibleTransformException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/sun/invoke/util/ValueConversions.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/invoke/util/ValueConversions.java Mon Sep 12 16:59:34 2011 -0700
@@ -677,9 +677,7 @@
EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
NEW_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "newArray", MethodType.methodType(Object[].class, int.class));
} catch (NoSuchMethodException | IllegalAccessException ex) {
- Error err = new InternalError("uncaught exception");
- err.initCause(ex);
- throw err;
+ throw new InternalError("uncaught exception", ex);
}
}
@@ -693,9 +691,7 @@
COPY_AS_PRIMITIVE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsPrimitiveArray", MethodType.methodType(Object.class, Wrapper.class, Object[].class));
MAKE_LIST = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeList", MethodType.methodType(List.class, Object[].class));
} catch (ReflectiveOperationException ex) {
- Error err = new InternalError("uncaught exception");
- err.initCause(ex);
- throw err;
+ throw new InternalError("uncaught exception", ex);
}
}
}
--- a/jdk/src/share/classes/sun/java2d/pipe/LoopPipe.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/java2d/pipe/LoopPipe.java Mon Sep 12 16:59:34 2011 -0700
@@ -281,9 +281,8 @@
} catch (Throwable t) {
sr.dispose();
sr = null;
- t.printStackTrace();
throw new InternalError("Unable to Stroke shape ("+
- t.getMessage()+")");
+ t.getMessage()+")", t);
}
return sr;
}
--- a/jdk/src/share/classes/sun/management/counter/perf/PerfDataEntry.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/management/counter/perf/PerfDataEntry.java Mon Sep 12 16:59:34 2011 -0700
@@ -133,7 +133,7 @@
catch (UnsupportedEncodingException e) {
// should not reach here
// "UTF-8" is always a known encoding
- throw new InternalError(e.getMessage());
+ throw new InternalError(e.getMessage(), e);
}
if (variability == Variability.INVALID) {
--- a/jdk/src/share/classes/sun/management/counter/perf/PerfDataType.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/management/counter/perf/PerfDataType.java Mon Sep 12 16:59:34 2011 -0700
@@ -93,7 +93,7 @@
this.value = b[0];
} catch (UnsupportedEncodingException e) {
// ignore, "UTF-8" is always a known encoding
- throw new InternalError("Unknown encoding");
+ throw new InternalError("Unknown encoding", e);
}
}
}
--- a/jdk/src/share/classes/sun/misc/Launcher.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/misc/Launcher.java Mon Sep 12 16:59:34 2011 -0700
@@ -71,7 +71,7 @@
extcl = ExtClassLoader.getExtClassLoader();
} catch (IOException e) {
throw new InternalError(
- "Could not create extension class loader");
+ "Could not create extension class loader", e);
}
// Now create the class loader to use to launch the application
@@ -79,7 +79,7 @@
loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
throw new InternalError(
- "Could not create application class loader");
+ "Could not create application class loader", e);
}
// Also set the context class loader for the primordial thread.
@@ -460,7 +460,7 @@
return ParseUtil.fileToEncodedURL(file);
} catch (MalformedURLException e) {
// Should never happen since we specify the protocol...
- throw new InternalError();
+ throw new InternalError(e);
}
}
@@ -475,15 +475,10 @@
try {
Class c = Class.forName(name);
return (URLStreamHandler)c.newInstance();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
+ } catch (ReflectiveOperationException e) {
+ throw new InternalError("could not load " + protocol +
+ "system protocol handler", e);
}
- throw new InternalError("could not load " + protocol +
- "system protocol handler");
}
}
}
--- a/jdk/src/share/classes/sun/misc/ProxyGenerator.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/misc/ProxyGenerator.java Mon Sep 12 16:59:34 2011 -0700
@@ -460,7 +460,7 @@
methods.add(generateStaticInitializer());
} catch (IOException e) {
- throw new InternalError("unexpected I/O Exception");
+ throw new InternalError("unexpected I/O Exception", e);
}
if (methods.size() > 65535) {
@@ -540,7 +540,7 @@
dout.writeShort(0); // (no ClassFile attributes for proxy classes)
} catch (IOException e) {
- throw new InternalError("unexpected I/O Exception");
+ throw new InternalError("unexpected I/O Exception", e);
}
return bout.toByteArray();
--- a/jdk/src/share/classes/sun/net/NetworkClient.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/net/NetworkClient.java Mon Sep 12 16:59:34 2011 -0700
@@ -139,7 +139,7 @@
serverSocket.getOutputStream()),
true, encoding);
} catch (UnsupportedEncodingException e) {
- throw new InternalError(encoding +"encoding not found");
+ throw new InternalError(encoding +"encoding not found", e);
}
serverInput = new BufferedInputStream(serverSocket.getInputStream());
}
--- a/jdk/src/share/classes/sun/net/NetworkServer.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/net/NetworkServer.java Mon Sep 12 16:59:34 2011 -0700
@@ -142,7 +142,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/sun/net/ftp/impl/FtpClient.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/net/ftp/impl/FtpClient.java Mon Sep 12 16:59:34 2011 -0700
@@ -905,7 +905,7 @@
out = new PrintStream(new BufferedOutputStream(server.getOutputStream()),
true, encoding);
} catch (UnsupportedEncodingException e) {
- throw new InternalError(encoding + "encoding not found");
+ throw new InternalError(encoding + "encoding not found", e);
}
in = new BufferedInputStream(server.getInputStream());
}
@@ -1621,7 +1621,7 @@
out = new PrintStream(new BufferedOutputStream(server.getOutputStream()),
true, encoding);
} catch (UnsupportedEncodingException e) {
- throw new InternalError(encoding + "encoding not found");
+ throw new InternalError(encoding + "encoding not found", e);
}
in = new BufferedInputStream(server.getInputStream());
}
@@ -2056,7 +2056,7 @@
out = new PrintStream(new BufferedOutputStream(server.getOutputStream()),
true, encoding);
} catch (UnsupportedEncodingException e) {
- throw new InternalError(encoding + "encoding not found");
+ throw new InternalError(encoding + "encoding not found", e);
}
in = new BufferedInputStream(server.getInputStream());
@@ -2090,7 +2090,7 @@
out = new PrintStream(new BufferedOutputStream(server.getOutputStream()),
true, encoding);
} catch (UnsupportedEncodingException e) {
- throw new InternalError(encoding + "encoding not found");
+ throw new InternalError(encoding + "encoding not found", e);
}
in = new BufferedInputStream(server.getInputStream());
--- a/jdk/src/share/classes/sun/net/smtp/SmtpClient.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/net/smtp/SmtpClient.java Mon Sep 12 16:59:34 2011 -0700
@@ -134,7 +134,7 @@
try {
message = new SmtpPrintStream(serverOutput, this);
} catch (UnsupportedEncodingException e) {
- throw new InternalError(encoding+" encoding not found");
+ throw new InternalError(encoding+" encoding not found", e);
}
return message;
}
--- a/jdk/src/share/classes/sun/net/www/http/ChunkedOutputStream.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/net/www/http/ChunkedOutputStream.java Mon Sep 12 16:59:34 2011 -0700
@@ -79,7 +79,7 @@
return header;
} catch (java.io.UnsupportedEncodingException e) {
/* This should never happen */
- throw new InternalError(e.getMessage());
+ throw new InternalError(e.getMessage(), e);
}
}
--- a/jdk/src/share/classes/sun/net/www/http/HttpClient.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/net/www/http/HttpClient.java Mon Sep 12 16:59:34 2011 -0700
@@ -395,7 +395,7 @@
new BufferedOutputStream(out),
false, encoding);
} catch (UnsupportedEncodingException e) {
- throw new InternalError(encoding+" encoding not found");
+ throw new InternalError(encoding+" encoding not found", e);
}
serverSocket.setTcpNoDelay(true);
}
--- a/jdk/src/share/classes/sun/net/www/protocol/gopher/GopherClient.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/net/www/protocol/gopher/GopherClient.java Mon Sep 12 16:59:34 2011 -0700
@@ -324,7 +324,7 @@
}
} catch (UnsupportedEncodingException e) {
- throw new InternalError(encoding+ " encoding not found");
+ throw new InternalError(encoding+ " encoding not found", e);
} catch (IOException e) {
} finally {
try {
--- a/jdk/src/share/classes/sun/net/www/protocol/https/HttpsClient.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/net/www/protocol/https/HttpsClient.java Mon Sep 12 16:59:34 2011 -0700
@@ -529,7 +529,7 @@
new BufferedOutputStream(serverSocket.getOutputStream()),
false, encoding);
} catch (UnsupportedEncodingException e) {
- throw new InternalError(encoding+" encoding not found");
+ throw new InternalError(encoding+" encoding not found", e);
}
// check URL spoofing if it has not been checked under handshaking
--- a/jdk/src/share/classes/sun/nio/ch/Util.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/nio/ch/Util.java Mon Sep 12 16:59:34 2011 -0700
@@ -373,7 +373,7 @@
NoSuchMethodException |
IllegalArgumentException |
ClassCastException x) {
- throw new InternalError();
+ throw new InternalError(x);
}
return null;
}});
@@ -395,7 +395,7 @@
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
return dbb;
}
@@ -418,7 +418,7 @@
NoSuchMethodException |
IllegalArgumentException |
ClassCastException x) {
- throw new InternalError();
+ throw new InternalError(x);
}
return null;
}});
@@ -440,7 +440,7 @@
} catch (InstantiationException |
IllegalAccessException |
InvocationTargetException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
return dbb;
}
--- a/jdk/src/share/classes/sun/nio/cs/AbstractCharsetProvider.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/nio/cs/AbstractCharsetProvider.java Mon Sep 12 16:59:34 2011 -0700
@@ -179,7 +179,9 @@
public Charset next() {
String csn = i.next();
- return lookup(csn);
+ synchronized (AbstractCharsetProvider.this) {
+ return lookup(csn);
+ }
}
public void remove() {
--- a/jdk/src/share/classes/sun/reflect/UTF8.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/reflect/UTF8.java Mon Sep 12 16:59:34 2011 -0700
@@ -52,7 +52,7 @@
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new InternalError
- ("Bug in sun.reflect bootstrap UTF-8 encoder");
+ ("Bug in sun.reflect bootstrap UTF-8 encoder", e);
}
return res;
}
--- a/jdk/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java Mon Sep 12 16:59:34 2011 -0700
@@ -25,9 +25,11 @@
package sun.reflect.generics.reflectiveObjects;
+import java.lang.annotation.Annotation;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
+import java.util.Objects;
import sun.reflect.generics.factory.GenericsFactory;
import sun.reflect.generics.tree.FieldTypeSignature;
@@ -178,4 +180,27 @@
public int hashCode() {
return genericDeclaration.hashCode() ^ name.hashCode();
}
+
+ // Currently vacuous implementations of AnnotatedElement methods.
+ public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
+ Objects.requireNonNull(annotationClass);
+ return false;
+ }
+
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+ Objects.requireNonNull(annotationClass);
+ return null;
+ }
+
+ public Annotation[] getAnnotations() {
+ // Since zero-length, don't need defensive clone
+ return EMPTY_ANNOTATION_ARRAY;
+ }
+
+ public Annotation[] getDeclaredAnnotations() {
+ // Since zero-length, don't need defensive clone
+ return EMPTY_ANNOTATION_ARRAY;
+ }
+
+ private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
}
--- a/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java Mon Sep 12 16:59:34 2011 -0700
@@ -292,7 +292,7 @@
}
});
} catch (Exception e) {
- throw new InternalError("bouncer cannot be found");
+ throw new InternalError("bouncer cannot be found", e);
}
}
--- a/jdk/src/share/classes/sun/rmi/transport/LiveRef.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/rmi/transport/LiveRef.java Mon Sep 12 16:59:34 2011 -0700
@@ -111,7 +111,7 @@
LiveRef newRef = (LiveRef) super.clone();
return newRef;
} catch (CloneNotSupportedException e) {
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
--- a/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java Mon Sep 12 16:59:34 2011 -0700
@@ -151,11 +151,36 @@
}
/**
+ * Obtains a key for a given etype of a principal with possible new salt
+ * and s2kparams
+ * @param cname NOT null
+ * @param password NOT null
+ * @param etype
+ * @param snp can be NULL
+ * @returns never null
+ */
+ public static EncryptionKey acquireSecretKey(PrincipalName cname,
+ char[] password, int etype, PAData.SaltAndParams snp)
+ throws KrbException {
+ String salt;
+ byte[] s2kparams;
+ if (snp != null) {
+ salt = snp.salt != null ? snp.salt : cname.getSalt();
+ s2kparams = snp.params;
+ } else {
+ salt = cname.getSalt();
+ s2kparams = null;
+ }
+ return acquireSecretKey(password, salt, etype, s2kparams);
+ }
+
+ /**
* Obtains a key for a given etype with salt and optional s2kparams
* @param password NOT null
* @param salt NOT null
* @param etype
* @param s2kparams can be NULL
+ * @returns never null
*/
public static EncryptionKey acquireSecretKey(char[] password,
String salt, int etype, byte[] s2kparams)
--- a/jdk/src/share/classes/sun/security/krb5/KrbAsRep.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/security/krb5/KrbAsRep.java Mon Sep 12 16:59:34 2011 -0700
@@ -131,13 +131,11 @@
KrbAsReq asReq, PrincipalName cname)
throws KrbException, Asn1Exception, IOException {
int encPartKeyType = rep.encPart.getEType();
- PAData.SaltAndParams snp =
- PAData.getSaltAndParams(encPartKeyType, rep.pAData);
- EncryptionKey dkey = null;
- dkey = EncryptionKey.acquireSecretKey(password,
- snp.salt == null ? cname.getSalt() : snp.salt,
+ EncryptionKey dkey = EncryptionKey.acquireSecretKey(
+ cname,
+ password,
encPartKeyType,
- snp.params);
+ PAData.getSaltAndParams(encPartKeyType, rep.pAData));
decrypt(dkey, asReq);
}
--- a/jdk/src/share/classes/sun/security/krb5/KrbAsReqBuilder.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/security/krb5/KrbAsReqBuilder.java Mon Sep 12 16:59:34 2011 -0700
@@ -169,34 +169,44 @@
* from a keytab on acceptor, but unfortunately (?) Java supports
* acceptor using password. In this case, if the service ticket is
* encrypted using an etype which we don't have PA-DATA new salt,
- * using the default salt is normally wrong (say, case-insensitive
+ * using the default salt might be wrong (say, case-insensitive
* user name). Instead, we would use the new salt of another etype.
*/
String salt = null; // the saved new salt
- for (int i=0; i<eTypes.length; i++) {
- PAData.SaltAndParams snp =
- PAData.getSaltAndParams(eTypes[i], paList);
- // First round, only calculate those with new salt
- if (snp.salt != null) {
- salt = snp.salt;
- result[i] = EncryptionKey.acquireSecretKey(password,
- snp.salt,
- eTypes[i],
- snp.params);
- }
- }
- if (salt == null) salt = cname.getSalt();
- for (int i=0; i<eTypes.length; i++) {
- // Second round, calculate those with no new salt
- if (result[i] == null) {
+ try {
+ for (int i=0; i<eTypes.length; i++) {
+ // First round, only calculate those have a PA entry
PAData.SaltAndParams snp =
PAData.getSaltAndParams(eTypes[i], paList);
- result[i] = EncryptionKey.acquireSecretKey(password,
- salt,
- eTypes[i],
- snp.params);
+ if (snp != null) {
+ // Never uses a salt for rc4-hmac, it does not use
+ // a salt at all
+ if (eTypes[i] != EncryptedData.ETYPE_ARCFOUR_HMAC &&
+ snp.salt != null) {
+ salt = snp.salt;
+ }
+ result[i] = EncryptionKey.acquireSecretKey(cname,
+ password,
+ eTypes[i],
+ snp);
+ }
}
+ // No new salt from PA, maybe empty, maybe only rc4-hmac
+ if (salt == null) salt = cname.getSalt();
+ for (int i=0; i<eTypes.length; i++) {
+ // Second round, calculate those with no PA entry
+ if (result[i] == null) {
+ result[i] = EncryptionKey.acquireSecretKey(password,
+ salt,
+ eTypes[i],
+ null);
+ }
+ }
+ } catch (IOException ioe) {
+ KrbException ke = new KrbException(Krb5.ASN1_PARSE_ERROR);
+ ke.initCause(ioe);
+ throw ke;
}
return result;
} else {
@@ -315,27 +325,19 @@
}
preAuthFailedOnce = true;
KRBError kerr = ke.getError();
+ int paEType = PAData.getPreferredEType(kerr.getPA(),
+ EType.getDefaults("default_tkt_enctypes")[0]);
if (password == null) {
EncryptionKey[] ks = Krb5Util.keysFromJavaxKeyTab(ktab, cname);
- pakey = EncryptionKey.findKey(kerr.getEType(), ks);
+ pakey = EncryptionKey.findKey(paEType, ks);
if (pakey != null) pakey = (EncryptionKey)pakey.clone();
for (EncryptionKey k: ks) k.destroy();
} else {
- PAData.SaltAndParams snp = PAData.getSaltAndParams(
- kerr.getEType(), kerr.getPA());
- if (kerr.getEType() == 0) {
- // Possible if PA-PW-SALT is in KRB-ERROR. RFC
- // does not recommend this
- pakey = EncryptionKey.acquireSecretKey(password,
- snp.salt == null ? cname.getSalt() : snp.salt,
- EType.getDefaults("default_tkt_enctypes")[0],
- null);
- } else {
- pakey = EncryptionKey.acquireSecretKey(password,
- snp.salt == null ? cname.getSalt() : snp.salt,
- kerr.getEType(),
- snp.params);
- }
+ pakey = EncryptionKey.acquireSecretKey(cname,
+ password,
+ paEType,
+ PAData.getSaltAndParams(
+ paEType, kerr.getPA()));
}
paList = kerr.getPA(); // Update current paList
} else {
--- a/jdk/src/share/classes/sun/security/krb5/internal/KRBError.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/security/krb5/internal/KRBError.java Mon Sep 12 16:59:34 2011 -0700
@@ -99,7 +99,6 @@
private Checksum eCksum; //optional
private PAData[] pa; // PA-DATA in eData
- private int pa_eType; // The 1st etype appeared in salt-related PAData
private static boolean DEBUG = Krb5.DEBUG;
@@ -266,50 +265,8 @@
DerValue tmp = derPA.data.getDerValue();
PAData pa_data = new PAData(tmp);
paList.add(pa_data);
- int pa_type = pa_data.getType();
- byte[] pa_value = pa_data.getValue();
if (DEBUG) {
- System.out.println(">>>Pre-Authentication Data:");
- System.out.println("\t PA-DATA type = " + pa_type);
- }
-
- switch(pa_type) {
- case Krb5.PA_ENC_TIMESTAMP:
- if (DEBUG) {
- System.out.println("\t PA-ENC-TIMESTAMP");
- }
- break;
- case Krb5.PA_ETYPE_INFO:
- if (pa_value != null) {
- DerValue der = new DerValue(pa_value);
- while (der.data.available() > 0) {
- DerValue value = der.data.getDerValue();
- ETypeInfo info = new ETypeInfo(value);
- if (pa_eType == 0) pa_eType = info.getEType();
- if (DEBUG) {
- System.out.println("\t PA-ETYPE-INFO etype = " + info.getEType());
- System.out.println("\t PA-ETYPE-INFO salt = " + info.getSalt());
- }
- }
- }
- break;
- case Krb5.PA_ETYPE_INFO2:
- if (pa_value != null) {
- DerValue der = new DerValue(pa_value);
- while (der.data.available() > 0) {
- DerValue value = der.data.getDerValue();
- ETypeInfo2 info2 = new ETypeInfo2(value);
- if (pa_eType == 0) pa_eType = info2.getEType();
- if (DEBUG) {
- System.out.println("\t PA-ETYPE-INFO2 etype = " + info2.getEType());
- System.out.println("\t PA-ETYPE-INFO2 salt = " + info2.getSalt());
- }
- }
- }
- break;
- default:
- // Unknown Pre-auth type
- break;
+ System.out.println(pa_data);
}
}
pa = paList.toArray(new PAData[paList.size()]);
@@ -340,10 +297,6 @@
return pa;
}
- public final int getEType() {
- return pa_eType;
- }
-
public final String getErrorString() {
return eText;
}
--- a/jdk/src/share/classes/sun/security/krb5/internal/PAData.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/security/krb5/internal/PAData.java Mon Sep 12 16:59:34 2011 -0700
@@ -139,9 +139,56 @@
}
/**
+ * Gets the preferred etype from the PAData array.
+ * 1. ETYPE-INFO2-ENTRY with unknown s2kparams ignored
+ * 2. ETYPE-INFO2 preferred to ETYPE-INFO
+ * 3. multiple entries for same etype in one PA-DATA, use the first one.
+ * 4. Multiple PA-DATA with same type, choose the last one
+ * (This is useful when PA-DATAs from KRB-ERROR and AS-REP are combined).
+ * @return the etype, or defaultEType if not enough info
+ * @throws Asn1Exception|IOException if there is an encoding error
+ */
+ public static int getPreferredEType(PAData[] pas, int defaultEType)
+ throws IOException, Asn1Exception {
+
+ if (pas == null) return defaultEType;
+
+ DerValue d = null, d2 = null;
+ for (PAData p: pas) {
+ if (p.getValue() == null) continue;
+ switch (p.getType()) {
+ case Krb5.PA_ETYPE_INFO:
+ d = new DerValue(p.getValue());
+ break;
+ case Krb5.PA_ETYPE_INFO2:
+ d2 = new DerValue(p.getValue());
+ break;
+ }
+ }
+ if (d2 != null) {
+ while (d2.data.available() > 0) {
+ DerValue value = d2.data.getDerValue();
+ ETypeInfo2 tmp = new ETypeInfo2(value);
+ if (tmp.getParams() == null) {
+ // we don't support non-null s2kparams
+ return tmp.getEType();
+ }
+ }
+ }
+ if (d != null) {
+ while (d.data.available() > 0) {
+ DerValue value = d.data.getDerValue();
+ ETypeInfo tmp = new ETypeInfo(value);
+ return tmp.getEType();
+ }
+ }
+ return defaultEType;
+ }
+
+ /**
* A place to store a pair of salt and s2kparams.
- * An empty salt is changed to null, to be interopable
- * with Windows 2000 server.
+ * An empty salt is changed to null, to be interoperable
+ * with Windows 2000 server. This is in fact not correct.
*/
public static class SaltAndParams {
public final String salt;
@@ -155,57 +202,120 @@
/**
* Fetches salt and s2kparams value for eType in a series of PA-DATAs.
- * The preference order is PA-ETYPE-INFO2 > PA-ETYPE-INFO > PA-PW-SALT.
- * If multiple PA-DATA for the same etype appears, use the last one.
+ * 1. ETYPE-INFO2-ENTRY with unknown s2kparams ignored
+ * 2. PA-ETYPE-INFO2 preferred to PA-ETYPE-INFO preferred to PA-PW-SALT.
+ * 3. multiple entries for same etype in one PA-DATA, use the first one.
+ * 4. Multiple PA-DATA with same type, choose the last one
* (This is useful when PA-DATAs from KRB-ERROR and AS-REP are combined).
- * @return salt and s2kparams. never null, its field might be null.
+ * @return salt and s2kparams. can be null if not found
*/
public static SaltAndParams getSaltAndParams(int eType, PAData[] pas)
- throws Asn1Exception, KrbException {
+ throws Asn1Exception, IOException {
- if (pas == null || pas.length == 0) {
- return new SaltAndParams(null, null);
- }
+ if (pas == null) return null;
+ DerValue d = null, d2 = null;
String paPwSalt = null;
- ETypeInfo2 info2 = null;
- ETypeInfo info = null;
for (PAData p: pas) {
- if (p.getValue() != null) {
- try {
- switch (p.getType()) {
- case Krb5.PA_PW_SALT:
- paPwSalt = new String(p.getValue(),
- KerberosString.MSNAME?"UTF8":"8859_1");
- break;
- case Krb5.PA_ETYPE_INFO:
- DerValue der = new DerValue(p.getValue());
- while (der.data.available() > 0) {
- DerValue value = der.data.getDerValue();
- ETypeInfo tmp = new ETypeInfo(value);
- if (tmp.getEType() == eType) info = tmp;
- }
- break;
- case Krb5.PA_ETYPE_INFO2:
- der = new DerValue(p.getValue());
- while (der.data.available() > 0) {
- DerValue value = der.data.getDerValue();
- ETypeInfo2 tmp = new ETypeInfo2(value);
- if (tmp.getEType() == eType) info2 = tmp;
- }
- break;
- }
- } catch (IOException ioe) {
- // Ignored
+ if (p.getValue() == null) continue;
+ switch (p.getType()) {
+ case Krb5.PA_PW_SALT:
+ paPwSalt = new String(p.getValue(),
+ KerberosString.MSNAME?"UTF8":"8859_1");
+ break;
+ case Krb5.PA_ETYPE_INFO:
+ d = new DerValue(p.getValue());
+ break;
+ case Krb5.PA_ETYPE_INFO2:
+ d2 = new DerValue(p.getValue());
+ break;
+ }
+ }
+ if (d2 != null) {
+ while (d2.data.available() > 0) {
+ DerValue value = d2.data.getDerValue();
+ ETypeInfo2 tmp = new ETypeInfo2(value);
+ if (tmp.getParams() == null && tmp.getEType() == eType) {
+ // we don't support non-null s2kparams
+ return new SaltAndParams(tmp.getSalt(), tmp.getParams());
+ }
+ }
+ }
+ if (d != null) {
+ while (d.data.available() > 0) {
+ DerValue value = d.data.getDerValue();
+ ETypeInfo tmp = new ETypeInfo(value);
+ if (tmp.getEType() == eType) {
+ return new SaltAndParams(tmp.getSalt(), null);
}
}
}
- if (info2 != null) {
- return new SaltAndParams(info2.getSalt(), info2.getParams());
- } else if (info != null) {
- return new SaltAndParams(info.getSalt(), null);
+ if (paPwSalt != null) {
+ return new SaltAndParams(paPwSalt, null);
}
- return new SaltAndParams(paPwSalt, null);
+ return null;
+ }
+
+ @Override
+ public String toString(){
+ StringBuilder sb = new StringBuilder();
+ sb.append(">>>Pre-Authentication Data:\n\t PA-DATA type = ")
+ .append(pADataType).append('\n');
+
+ switch(pADataType) {
+ case Krb5.PA_ENC_TIMESTAMP:
+ sb.append("\t PA-ENC-TIMESTAMP");
+ break;
+ case Krb5.PA_ETYPE_INFO:
+ if (pADataValue != null) {
+ try {
+ DerValue der = new DerValue(pADataValue);
+ while (der.data.available() > 0) {
+ DerValue value = der.data.getDerValue();
+ ETypeInfo info = new ETypeInfo(value);
+ sb.append("\t PA-ETYPE-INFO etype = ")
+ .append(info.getEType())
+ .append(", salt = ")
+ .append(info.getSalt())
+ .append('\n');
+ }
+ } catch (IOException|Asn1Exception e) {
+ sb.append("\t <Unparseable PA-ETYPE-INFO>\n");
+ }
+ }
+ break;
+ case Krb5.PA_ETYPE_INFO2:
+ if (pADataValue != null) {
+ try {
+ DerValue der = new DerValue(pADataValue);
+ while (der.data.available() > 0) {
+ DerValue value = der.data.getDerValue();
+ ETypeInfo2 info2 = new ETypeInfo2(value);
+ sb.append("\t PA-ETYPE-INFO2 etype = ")
+ .append(info2.getEType())
+ .append(", salt = ")
+ .append(info2.getSalt())
+ .append(", s2kparams = ");
+ byte[] s2kparams = info2.getParams();
+ if (s2kparams == null) {
+ sb.append("null\n");
+ } else if (s2kparams.length == 0) {
+ sb.append("empty\n");
+ } else {
+ sb.append(new sun.misc.HexDumpEncoder()
+ .encodeBuffer(s2kparams));
+ }
+ }
+ } catch (IOException|Asn1Exception e) {
+ sb.append("\t <Unparseable PA-ETYPE-INFO>\n");
+ }
+ }
+ break;
+ default:
+ // Unknown Pre-auth type
+ break;
+ }
+ return sb.toString();
}
}
--- a/jdk/src/share/classes/sun/security/provider/SecureRandom.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/security/provider/SecureRandom.java Mon Sep 12 16:59:34 2011 -0700
@@ -249,7 +249,7 @@
try {
digest = MessageDigest.getInstance ("SHA");
} catch (NoSuchAlgorithmException e) {
- throw new InternalError("internal error: SHA-1 not available.");
+ throw new InternalError("internal error: SHA-1 not available.", e);
}
}
}
--- a/jdk/src/share/classes/sun/security/provider/SeedGenerator.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/security/provider/SeedGenerator.java Mon Sep 12 16:59:34 2011 -0700
@@ -151,7 +151,8 @@
try {
md = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException nsae) {
- throw new InternalError("internal error: SHA-1 not available.");
+ throw new InternalError("internal error: SHA-1 not available."
+ , nsae);
}
// The current time in millis
@@ -258,7 +259,8 @@
try {
digest = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException e) {
- throw new InternalError("internal error: SHA-1 not available.");
+ throw new InternalError("internal error: SHA-1 not available."
+ , e);
}
final ThreadGroup[] finalsg = new ThreadGroup[1];
@@ -311,7 +313,8 @@
t.start();
} catch (Exception e) {
throw new InternalError("internal error: " +
- "SeedGenerator thread creation error.");
+ "SeedGenerator thread creation error."
+ , e);
}
// We wait 250milli quanta, so the minimum wait time
@@ -344,7 +347,8 @@
}
} catch (Exception e) {
throw new InternalError("internal error: " +
- "SeedGenerator thread generated an exception.");
+ "SeedGenerator thread generated an exception."
+ , e);
}
}
@@ -367,7 +371,8 @@
} catch (Exception e) {
if (count <= 0)
throw new InternalError("internal error: " +
- "SeedGenerator thread generated an exception.");
+ "SeedGenerator thread generated an exception."
+ ,e);
}
synchronized(this) {
@@ -533,7 +538,7 @@
} catch (IOException ioe) {
throw new InternalError("URLSeedGenerator " + deviceName +
" generated exception: " +
- ioe.getMessage());
+ ioe.getMessage(), ioe);
}
}
--- a/jdk/src/share/classes/sun/security/provider/certpath/ForwardState.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/security/provider/certpath/ForwardState.java Mon Sep 12 16:59:34 2011 -0700
@@ -262,7 +262,7 @@
= (HashSet<GeneralNameInterface>)subjectNamesTraversed.clone();
return clonedState;
} catch (CloneNotSupportedException e) {
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
}
--- a/jdk/src/share/classes/sun/security/provider/certpath/ReverseState.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/security/provider/certpath/ReverseState.java Mon Sep 12 16:59:34 2011 -0700
@@ -394,7 +394,7 @@
return clonedState;
} catch (CloneNotSupportedException e) {
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
}
--- a/jdk/src/share/classes/sun/security/provider/certpath/URICertStore.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/security/provider/certpath/URICertStore.java Mon Sep 12 16:59:34 2011 -0700
@@ -494,7 +494,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
/* Cannot happen */
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
}
--- a/jdk/src/share/classes/sun/security/tools/JarSigner.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/security/tools/JarSigner.java Mon Sep 12 16:59:34 2011 -0700
@@ -1506,6 +1506,9 @@
CertPath cp = certificateFactory.generateCertPath(certs);
validator.validate(cp, pkixParameters);
} catch (Exception e) {
+ if (debug) {
+ e.printStackTrace();
+ }
chainNotValidated = true;
s.append(tab + rb.getString(".CertPath.not.validated.") +
e.getLocalizedMessage() + "]\n"); // TODO
@@ -1562,6 +1565,27 @@
}
try {
+
+ certificateFactory = CertificateFactory.getInstance("X.509");
+ validator = CertPathValidator.getInstance("PKIX");
+ Set<TrustAnchor> tas = new HashSet<>();
+ try {
+ KeyStore caks = KeyTool.getCacertsKeyStore();
+ if (caks != null) {
+ Enumeration<String> aliases = caks.aliases();
+ while (aliases.hasMoreElements()) {
+ String a = aliases.nextElement();
+ try {
+ tas.add(new TrustAnchor((X509Certificate)caks.getCertificate(a), null));
+ } catch (Exception e2) {
+ // ignore, when a SecretkeyEntry does not include a cert
+ }
+ }
+ }
+ } catch (Exception e) {
+ // Ignore, if cacerts cannot be loaded
+ }
+
if (providerName == null) {
store = KeyStore.getInstance(storetype);
} else {
@@ -1580,45 +1604,28 @@
(rb.getString("Enter.Passphrase.for.keystore."));
}
- if (nullStream) {
- store.load(null, storepass);
- } else {
- keyStoreName = keyStoreName.replace(File.separatorChar, '/');
- URL url = null;
- try {
- url = new URL(keyStoreName);
- } catch (java.net.MalformedURLException e) {
- // try as file
- url = new File(keyStoreName).toURI().toURL();
- }
- InputStream is = null;
- try {
- is = url.openStream();
- store.load(is, storepass);
- } finally {
- if (is != null) {
- is.close();
+ try {
+ if (nullStream) {
+ store.load(null, storepass);
+ } else {
+ keyStoreName = keyStoreName.replace(File.separatorChar, '/');
+ URL url = null;
+ try {
+ url = new URL(keyStoreName);
+ } catch (java.net.MalformedURLException e) {
+ // try as file
+ url = new File(keyStoreName).toURI().toURL();
}
- }
- }
- Set<TrustAnchor> tas = new HashSet<>();
- try {
- KeyStore caks = KeyTool.getCacertsKeyStore();
- if (caks != null) {
- Enumeration<String> aliases = caks.aliases();
- while (aliases.hasMoreElements()) {
- String a = aliases.nextElement();
- try {
- tas.add(new TrustAnchor((X509Certificate)caks.getCertificate(a), null));
- } catch (Exception e2) {
- // ignore, when a SecretkeyEntry does not include a cert
+ InputStream is = null;
+ try {
+ is = url.openStream();
+ store.load(is, storepass);
+ } finally {
+ if (is != null) {
+ is.close();
}
}
}
- } catch (Exception e) {
- // Ignore, if cacerts cannot be loaded
- }
- if (store != null) {
Enumeration<String> aliases = store.aliases();
while (aliases.hasMoreElements()) {
String a = aliases.nextElement();
@@ -1634,14 +1641,13 @@
// ignore, when a SecretkeyEntry does not include a cert
}
}
- }
- certificateFactory = CertificateFactory.getInstance("X.509");
- validator = CertPathValidator.getInstance("PKIX");
- try {
- pkixParameters = new PKIXParameters(tas);
- pkixParameters.setRevocationEnabled(false);
- } catch (InvalidAlgorithmParameterException ex) {
- // Only if tas is empty
+ } finally {
+ try {
+ pkixParameters = new PKIXParameters(tas);
+ pkixParameters.setRevocationEnabled(false);
+ } catch (InvalidAlgorithmParameterException ex) {
+ // Only if tas is empty
+ }
}
} catch (IOException ioe) {
throw new RuntimeException(rb.getString("keystore.load.") +
@@ -1805,6 +1811,9 @@
CertPath cp = certificateFactory.generateCertPath(Arrays.asList(certChain));
validator.validate(cp, pkixParameters);
} catch (Exception e) {
+ if (debug) {
+ e.printStackTrace();
+ }
chainNotValidated = true;
}
--- a/jdk/src/share/classes/sun/security/tools/KeyTool.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java Mon Sep 12 16:59:34 2011 -0700
@@ -1141,17 +1141,14 @@
if (token) {
keyStore.store(null, null);
} else {
- FileOutputStream fout = null;
- try {
- fout = (nullStream ?
- (FileOutputStream)null :
- new FileOutputStream(ksfname));
- keyStore.store
- (fout,
- (storePassNew!=null) ? storePassNew : storePass);
- } finally {
- if (fout != null) {
- fout.close();
+ char[] pass = (storePassNew!=null) ? storePassNew : storePass;
+ if (nullStream) {
+ keyStore.store(null, pass);
+ } else {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ keyStore.store(bout, pass);
+ try (FileOutputStream fout = new FileOutputStream(ksfname)) {
+ fout.write(bout.toByteArray());
}
}
}
@@ -1399,7 +1396,7 @@
private char[] promptForKeyPass(String alias, String orig, char[] origPass) throws Exception{
if (P12KEYSTORE.equalsIgnoreCase(storetype)) {
return origPass;
- } else if (!token) {
+ } else if (!token && !protectedPath) {
// Prompt for key password
int count;
for (count = 0; count < 3; count++) {
@@ -1446,7 +1443,7 @@
}
}
}
- return null; // PKCS11
+ return null; // PKCS11, MSCAPI, or -protected
}
/**
* Creates a new secret key.
--- a/jdk/src/share/classes/sun/security/util/SecurityConstants.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/security/util/SecurityConstants.java Mon Sep 12 16:59:34 2011 -0700
@@ -127,10 +127,8 @@
// AWT present
try {
return (PermissionFactory<?>)c.newInstance();
- } catch (InstantiationException x) {
- throw new InternalError(x.getMessage());
- } catch (IllegalAccessException x) {
- throw new InternalError(x.getMessage());
+ } catch (ReflectiveOperationException x) {
+ throw new InternalError(x.getMessage(), x);
}
} else {
// AWT not present
--- a/jdk/src/share/classes/sun/text/CompactByteArray.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/text/CompactByteArray.java Mon Sep 12 16:59:34 2011 -0700
@@ -269,7 +269,7 @@
if (hashes != null) other.hashes = (int[])hashes.clone();
return other;
} catch (CloneNotSupportedException e) {
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/sun/text/normalizer/NormalizerBase.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/text/normalizer/NormalizerBase.java Mon Sep 12 16:59:34 2011 -0700
@@ -636,7 +636,7 @@
return copy;
}
catch (CloneNotSupportedException e) {
- throw new InternalError(e.toString());
+ throw new InternalError(e.toString(), e);
}
}
--- a/jdk/src/share/classes/sun/tools/attach/HotSpotAttachProvider.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/tools/attach/HotSpotAttachProvider.java Mon Sep 12 16:59:34 2011 -0700
@@ -89,7 +89,7 @@
if (t instanceof SecurityException) {
return result;
}
- throw new InternalError(); // shouldn't happen
+ throw new InternalError(t); // shouldn't happen
}
for (Object vmid: vms) {
--- a/jdk/src/share/classes/sun/tools/attach/HotSpotVirtualMachine.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/tools/attach/HotSpotVirtualMachine.java Mon Sep 12 16:59:34 2011 -0700
@@ -102,7 +102,7 @@
try {
loadAgentLibrary("instrument", args);
} catch (AgentLoadException x) {
- throw new InternalError("instrument library is missing in target VM");
+ throw new InternalError("instrument library is missing in target VM", x);
} catch (AgentInitializationException x) {
/*
* Translate interesting errors into the right exception and
@@ -212,7 +212,7 @@
try {
return execute(cmd, args);
} catch (AgentLoadException x) {
- throw new InternalError("Should not get here");
+ throw new InternalError("Should not get here", x);
}
}
--- a/jdk/src/share/classes/sun/tools/jconsole/LocalVirtualMachine.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/tools/jconsole/LocalVirtualMachine.java Mon Sep 12 16:59:34 2011 -0700
@@ -135,10 +135,8 @@
try {
host = MonitoredHost.getMonitoredHost(new HostIdentifier((String)null));
vms = host.activeVms();
- } catch (java.net.URISyntaxException sx) {
- throw new InternalError(sx.getMessage());
- } catch (MonitorException mx) {
- throw new InternalError(mx.getMessage());
+ } catch (java.net.URISyntaxException | MonitorException x) {
+ throw new InternalError(x.getMessage(), x);
}
for (Object vmid: vms) {
if (vmid instanceof Integer) {
--- a/jdk/src/share/classes/sun/tools/tree/Node.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/tools/tree/Node.java Mon Sep 12 16:59:34 2011 -0700
@@ -108,7 +108,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/share/classes/sun/tracing/dtrace/DTraceProvider.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/tracing/dtrace/DTraceProvider.java Mon Sep 12 16:59:34 2011 -0700
@@ -26,18 +26,15 @@
package sun.tracing.dtrace;
import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.annotation.Annotation;
-import java.util.HashMap;
import sun.tracing.ProviderSkeleton;
import sun.tracing.ProbeSkeleton;
import com.sun.tracing.Provider;
-import com.sun.tracing.ProviderName;
import com.sun.tracing.ProbeName;
import com.sun.tracing.dtrace.Attributes;
import com.sun.tracing.dtrace.ModuleName;
@@ -140,14 +137,8 @@
try {
Constructor cons = proxyClass.getConstructor(constructorParams);
return (T)cons.newInstance(new Object[] { this });
- } catch (NoSuchMethodException e) {
- throw new InternalError(e.toString());
- } catch (IllegalAccessException e) {
- throw new InternalError(e.toString());
- } catch (InstantiationException e) {
- throw new InternalError(e.toString());
- } catch (InvocationTargetException e) {
- throw new InternalError(e.toString());
+ } catch (ReflectiveOperationException e) {
+ throw new InternalError(e.toString(), e);
}
}
--- a/jdk/src/share/classes/sun/util/calendar/CalendarDate.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/share/classes/sun/util/calendar/CalendarDate.java Mon Sep 12 16:59:34 2011 -0700
@@ -435,7 +435,7 @@
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen
- throw new InternalError();
+ throw new InternalError(e);
}
}
--- a/jdk/src/solaris/classes/sun/awt/X11/XBaseMenuWindow.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/solaris/classes/sun/awt/X11/XBaseMenuWindow.java Mon Sep 12 16:59:34 2011 -0700
@@ -157,7 +157,7 @@
try {
return super.clone();
} catch (CloneNotSupportedException ex) {
- throw new InternalError();
+ throw new InternalError(ex);
}
}
--- a/jdk/src/solaris/classes/sun/awt/X11/XMenuItemPeer.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/solaris/classes/sun/awt/X11/XMenuItemPeer.java Mon Sep 12 16:59:34 2011 -0700
@@ -131,7 +131,7 @@
try {
return super.clone();
} catch (CloneNotSupportedException ex) {
- throw new InternalError();
+ throw new InternalError(ex);
}
}
--- a/jdk/src/solaris/classes/sun/nio/ch/InheritedChannel.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/solaris/classes/sun/nio/ch/InheritedChannel.java Mon Sep 12 16:59:34 2011 -0700
@@ -64,7 +64,7 @@
dup2(devnull, 2);
} catch (IOException ioe) {
// this shouldn't happen
- throw new InternalError();
+ throw new InternalError(ioe);
}
}
--- a/jdk/src/solaris/classes/sun/tools/attach/LinuxVirtualMachine.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/solaris/classes/sun/tools/attach/LinuxVirtualMachine.java Mon Sep 12 16:59:34 2011 -0700
@@ -304,7 +304,7 @@
try {
b = s.getBytes("UTF-8");
} catch (java.io.UnsupportedEncodingException x) {
- throw new InternalError();
+ throw new InternalError(x);
}
LinuxVirtualMachine.write(fd, b, 0, b.length);
}
--- a/jdk/src/windows/native/com/sun/security/auth/module/nt.c Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/windows/native/com/sun/security/auth/module/nt.c Mon Sep 12 16:59:34 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -43,6 +43,19 @@
BOOL getTextualSid(PSID pSid, LPTSTR TextualSid, LPDWORD lpdwBufferLen);
void DisplayErrorText(DWORD dwLastError);
+JNIEXPORT jlong JNICALL
+Java_com_sun_security_auth_module_NTSystem_getImpersonationToken0
+ (JNIEnv *env, jobject obj) {
+ HANDLE impersonationToken = 0; // impersonation token
+ if (debug) {
+ printf("getting impersonation token\n");
+ }
+ if (getImpersonationToken(&impersonationToken) == FALSE) {
+ return 0;
+ }
+ return (jlong)impersonationToken;
+}
+
JNIEXPORT void JNICALL
Java_com_sun_security_auth_module_NTSystem_getCurrent
(JNIEnv *env, jobject obj, jboolean debugNative) {
@@ -59,7 +72,6 @@
DWORD numGroups = 0; // num groups
LPTSTR *groups = NULL; // groups array
long pIndex = -1; // index of primaryGroup in groups array
- HANDLE impersonationToken = 0; // impersonation token
jfieldID fid;
jstring jstr;
@@ -100,13 +112,6 @@
return;
}
- if (debug) {
- printf("getting impersonation token\n");
- }
- if (getImpersonationToken(&impersonationToken) == FALSE) {
- return;
- }
-
// then set values into NTSystem
fid = (*env)->GetFieldID(env, cls, "userName", "Ljava/lang/String;");
@@ -233,18 +238,6 @@
(*env)->SetObjectField(env, obj, fid, jgroups);
}
- fid = (*env)->GetFieldID(env, cls, "impersonationToken", "J");
- if (fid == 0) {
- jclass newExcCls =
- (*env)->FindClass(env, "java/lang/IllegalArgumentException");
- if (newExcCls == 0) {
- systemError = TRUE;
- goto out;
- }
- (*env)->ThrowNew(env, newExcCls, "invalid field: impersonationToken");
- }
- (*env)->SetLongField(env, obj, fid, (jlong)impersonationToken);
-
out:
if (userName != NULL) {
HeapFree(GetProcessHeap(), 0, userName);
@@ -269,6 +262,7 @@
}
HeapFree(GetProcessHeap(), 0, groups);
}
+ CloseHandle(tokenHandle);
if (systemError && debug) {
printf(" [getCurrent] System Error: ");
@@ -592,6 +586,7 @@
}
return FALSE;
}
+ CloseHandle(dupToken);
if (debug) {
printf(" [getImpersonationToken] token = %d\n", *impersonationToken);
@@ -802,6 +797,8 @@
}
HeapFree(GetProcessHeap(), 0, groups);
}
+ CloseHandle(impersonationToken);
+ CloseHandle(tokenHandle);
}
*/
--- a/jdk/src/windows/native/java/net/NetworkInterface.c Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/windows/native/java/net/NetworkInterface.c Mon Sep 12 16:59:34 2011 -0700
@@ -504,8 +504,7 @@
*/
if (netaddrCount < 0) {
netaddrCount = enumAddresses_win(env, ifs, &netaddrP);
- if ((*env)->ExceptionOccurred(env)) {
- free_netaddr(netaddrP);
+ if (netaddrCount == -1) {
return NULL;
}
}
--- a/jdk/src/windows/native/java/net/NetworkInterface_winXP.c Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/windows/native/java/net/NetworkInterface_winXP.c Mon Sep 12 16:59:34 2011 -0700
@@ -194,8 +194,7 @@
while (curr != NULL) {
netaddr *netaddrP;
ret = enumAddresses_win(env, curr, &netaddrP);
- if ((*env)->ExceptionOccurred(env)) {
- free_netaddr(netaddrP);
+ if (ret == -1) {
return -1;
}
curr->addrs = netaddrP;
@@ -449,8 +448,7 @@
*/
if (netaddrCount < 0) {
netaddrCount = enumAddresses_win(env, ifs, &netaddrP);
- if ((*env)->ExceptionOccurred(env)) {
- free_netaddr(netaddrP);
+ if (netaddrCount == -1) {
return NULL;
}
}
--- a/jdk/src/windows/native/java/net/TwoStacksPlainSocketImpl.c Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/src/windows/native/java/net/TwoStacksPlainSocketImpl.c Mon Sep 12 16:59:34 2011 -0700
@@ -576,6 +576,7 @@
{
/* fields on this */
jint port;
+ jint scope;
jint timeout = (*env)->GetIntField(env, this, psi_timeoutID);
jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
@@ -755,7 +756,11 @@
addr = (*env)->GetObjectField (env, socketAddressObj, ia6_ipaddressID);
(*env)->SetByteArrayRegion (env, addr, 0, 16, (const char *)&him.him6.sin6_addr);
(*env)->SetIntField(env, socketAddressObj, ia_familyID, IPv6);
- (*env)->SetIntField(env, socketAddressObj, ia6_scopeidID, him.him6.sin6_scope_id);
+ scope = him.him6.sin6_scope_id;
+ (*env)->SetIntField(env, socketAddressObj, ia6_scopeidID, scope);
+ if(scope>0) {
+ (*env)->SetBooleanField(env, socketAddressObj, ia6_scopeidsetID, JNI_TRUE);
+ }
}
/* fields common to AF_INET and AF_INET6 */
--- a/jdk/test/Makefile Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/Makefile Mon Sep 12 16:59:34 2011 -0700
@@ -423,7 +423,8 @@
# Stable othervm testruns (minus items from PROBLEM_LIST)
# Using samevm has problems, and doesn't help performance as much as others.
JDK_ALL_TARGETS += jdk_awt
-jdk_awt: $(call TestDirs, com/sun/awt java/awt sun/awt)
+jdk_awt: $(call TestDirs, com/sun/awt java/awt sun/awt \
+ javax/imageio javax/print sun/pisces)
$(call RunOthervmBatch)
# Stable samevm testruns (minus items from PROBLEM_LIST)
@@ -486,9 +487,8 @@
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_misc
jdk_misc: $(call TestDirs, \
- demo javax/imageio javax/naming javax/print javax/script \
- javax/smartcardio javax/sound com/sun/java com/sun/jndi \
- com/sun/org com/sun/xml sun/misc sun/pisces)
+ demo/jvmti demo/zipfs javax/naming javax/script \
+ javax/smartcardio com/sun/jndi com/sun/xml sun/misc)
$(call RunSamevmBatch)
# Stable samevm testruns (minus items from PROBLEM_LIST)
@@ -532,17 +532,15 @@
jdk_security1: $(call TestDirs, java/security)
$(call RunSamevmBatch)
-# Stable othervm testruns (minus items from PROBLEM_LIST)
-# Using samevm has serious problems with these tests
+# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_security2
-jdk_security2: $(call TestDirs, javax/crypto com/sun/crypto)
+jdk_security2: $(call TestDirs, javax/crypto javax/xml/crypto com/sun/crypto)
$(call RunSamevmBatch)
-# Stable othervm testruns (minus items from PROBLEM_LIST)
-# Using samevm has serious problems with these tests
+# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_security3
-jdk_security3: $(call TestDirs, com/sun/security lib/security \
- javax/security sun/security)
+jdk_security3: $(call TestDirs, com/sun/security lib/security javax/security \
+ sun/security com/sun/org/apache/xml/internal/security)
$(call SharedLibraryPermissions,sun/security)
$(call RunSamevmBatch)
@@ -550,10 +548,16 @@
jdk_security: jdk_security1 jdk_security2 jdk_security3
@$(SummaryInfo)
+# Stable samevm testruns (minus items from PROBLEM_LIST)
+JDK_ALL_TARGETS += jdk_sound
+jdk_sound: $(call TestDirs, javax/sound)
+ $(call RunSamevmBatch)
+
# Stable othervm testruns (minus items from PROBLEM_LIST)
# Using samevm has problems, and doesn't help performance as much as others.
JDK_ALL_TARGETS += jdk_swing
-jdk_swing: $(call TestDirs, javax/swing sun/java2d)
+jdk_swing: $(call TestDirs, javax/swing sun/java2d \
+ demo/jfc com/sun/java/swing)
$(call RunOthervmBatch)
# Stable samevm testruns (minus items from PROBLEM_LIST)
@@ -802,17 +806,17 @@
# The jtjck.jar utility to use to run the tests
JTJCK_JAR = $(JCK_HOME)/lib/jtjck.jar
JTJCK_JAVA_ARGS = -XX:MaxPermSize=256m -Xmx512m
-JTJCK_OPTIONS = -headless -v
+JTJCK_OPTIONS = -headless -v
# Default tests to run
ifndef JCK_COMPILER_TESTS
- JCK_COMPILER_TESTS =
+ JCK_COMPILER_TESTS =
endif
ifndef JCK_RUNTIME_TESTS
- JCK_RUNTIME_TESTS =
+ JCK_RUNTIME_TESTS =
endif
ifndef JCK_DEVTOOLS_TESTS
- JCK_DEVTOOLS_TESTS =
+ JCK_DEVTOOLS_TESTS =
endif
# Generic rule used to run jck tests
@@ -838,14 +842,14 @@
_generic_jck_tests
# JCK7 runtime tests
-jck7runtime:
+jck7runtime:
$(MAKE) UNIQUE_DIR=$@ \
JCK_HOME=$(JCK7RUNTIME_HOME) \
TESTDIRS="$(JCK_RUNTIME_TESTS)" \
_generic_jck_tests
# JCK7 devtools tests
-jck7devtools:
+jck7devtools:
$(MAKE) UNIQUE_DIR=$@ \
JCK_HOME=$(JCK7DEVTOOLS_HOME) \
TESTDIRS="$(JCK_DEVTOOLS_TESTS)" \
--- a/jdk/test/ProblemList.txt Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/ProblemList.txt Mon Sep 12 16:59:34 2011 -0700
@@ -526,6 +526,16 @@
# 7081817
sun/security/provider/certpath/X509CertPath/IllegalCertiticates.java generic-all
+# 7041639, Solaris DSA keypair generation bug (Note: jdk_util also affected)
+java/security/KeyPairGenerator/SolarisShortDSA.java solaris-all
+sun/security/tools/jarsigner/onlymanifest.sh solaris-all
+sun/security/tools/jarsigner/ts.sh solaris-all
+sun/security/tools/keytool/emptysubject.sh solaris-all
+sun/security/tools/keytool/importreadall.sh solaris-all
+sun/security/tools/keytool/readjar.sh solaris-all
+sun/security/tools/keytool/selfissued.sh solaris-all
+sun/security/tools/keytool/standard.sh solaris-all
+
############################################################################
# jdk_swing (not using samevm)
@@ -586,5 +596,8 @@
# Filed 6772009
java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java generic-all
+# 7041639, Solaris DSA keypair generation bug
+java/util/TimeZone/TimeZoneDatePermissionCheck.sh solaris-all
+
############################################################################
--- a/jdk/test/com/sun/servicetag/JavaServiceTagTest.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/com/sun/servicetag/JavaServiceTagTest.java Mon Sep 12 16:59:34 2011 -0700
@@ -25,7 +25,7 @@
/*
* @test
- * @bug 6622366
+ * @bug 6622366 7078024
* @summary Basic Test for ServiceTag.getJavaServiceTag()
* Disable creating the service tag in the system registry.
* Verify the existence of registration.xml file and the
@@ -86,23 +86,42 @@
}
}
+ /**
+ * Tests if the running platform is a JDK.
+ */
+ static boolean isJDK() {
+ // Determine the JRE path by checking the existence of
+ // <HOME>/jre/lib and <HOME>/lib.
+ String javaHome = System.getProperty("java.home");
+ String jrepath = javaHome + File.separator + "jre";
+ File f = new File(jrepath, "lib");
+ if (!f.exists()) {
+ // java.home usually points to the JRE path
+ jrepath = javaHome;
+ }
+
+ return jrepath.endsWith(File.separator + "jre");
+ }
+
private static void checkServiceTag(ServiceTag st) throws IOException {
- Properties props = loadSwordfishEntries();
- if (st.getProductURN().
- equals(props.getProperty("servicetag.jdk.urn"))) {
- if (!st.getProductName().
- equals(props.getProperty("servicetag.jdk.name"))) {
- throw new RuntimeException("Product URN and name don't match.");
- }
- } else if (st.getProductURN().
- equals(props.getProperty("servicetag.jre.urn"))) {
- if (!st.getProductName().
- equals(props.getProperty("servicetag.jre.name"))) {
+ Properties props = loadServiceTagProps();
+ // jdk 8 and later, JDK and JRE have the same product URN.
+ String jdkUrn = props.getProperty("servicetag.jdk.urn");
+ String jreUrn = props.getProperty("servicetag.jre.urn");
+ boolean isJdk = isJDK();
+
+ if (isJdk) {
+ if (!st.getProductURN().equals(jdkUrn) ||
+ !st.getProductName().equals(
+ props.getProperty("servicetag.jdk.name"))) {
throw new RuntimeException("Product URN and name don't match.");
}
} else {
- throw new RuntimeException("Unexpected product_urn: " +
- st.getProductURN());
+ if (!st.getProductURN().equals(jreUrn) ||
+ !st.getProductName().equals(
+ props.getProperty("servicetag.jre.name"))) {
+ throw new RuntimeException("Product URN and name don't match.");
+ }
}
if (!st.getProductVersion().
equals(System.getProperty("java.version"))) {
@@ -160,18 +179,13 @@
}
}
- private static Properties loadSwordfishEntries()
+ private static Properties loadServiceTagProps()
throws IOException {
- int version = sun.misc.Version.jdkMinorVersion();
- String filename = "/com/sun/servicetag/resources/javase_" +
- version + "_swordfish.properties";
- InputStream in = Installer.class.getClass().getResourceAsStream(filename);
- Properties props = new Properties();
- try {
+ String filename = "/com/sun/servicetag/resources/javase_servicetag.properties";
+ try (InputStream in = Installer.class.getClass().getResourceAsStream(filename)) {
+ Properties props = new Properties();
props.load(in);
- } finally {
- in.close();
+ return props;
}
- return props;
}
}
--- a/jdk/test/com/sun/servicetag/JavaServiceTagTest1.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/com/sun/servicetag/JavaServiceTagTest1.java Mon Sep 12 16:59:34 2011 -0700
@@ -25,7 +25,7 @@
/*
* @test
- * @bug 6622366
+ * @bug 6622366 7078024
* @summary Basic Test for ServiceTag.getJavaServiceTag(String)
* to verify that the registration.xml and servicetag files
* are both created correctly.
@@ -157,25 +157,45 @@
return svctag;
}
+ /**
+ * Tests if the running platform is a JDK.
+ */
+ static boolean isJDK() {
+ // Determine the JRE path by checking the existence of
+ // <HOME>/jre/lib and <HOME>/lib.
+ String javaHome = System.getProperty("java.home");
+ String jrepath = javaHome + File.separator + "jre";
+ File f = new File(jrepath, "lib");
+ if (!f.exists()) {
+ // java.home usually points to the JRE path
+ jrepath = javaHome;
+ }
+
+ return jrepath.endsWith(File.separator + "jre");
+ }
+
private static void checkServiceTag(ServiceTag st, String source)
throws IOException {
- Properties props = loadSwordfishEntries();
- if (st.getProductURN().
- equals(props.getProperty("servicetag.jdk.urn"))) {
- if (!st.getProductName().
- equals(props.getProperty("servicetag.jdk.name"))) {
- throw new RuntimeException("Product URN and name don't match.");
- }
- } else if (st.getProductURN().
- equals(props.getProperty("servicetag.jre.urn"))) {
- if (!st.getProductName().
- equals(props.getProperty("servicetag.jre.name"))) {
+ Properties props = loadServiceTagProps();
+ // jdk 8 and later, JDK and JRE have the same product URN.
+ String jdkUrn = props.getProperty("servicetag.jdk.urn");
+ String jreUrn = props.getProperty("servicetag.jre.urn");
+ boolean isJdk = isJDK();
+
+ if (isJdk) {
+ if (!st.getProductURN().equals(jdkUrn) ||
+ !st.getProductName().equals(
+ props.getProperty("servicetag.jdk.name"))) {
throw new RuntimeException("Product URN and name don't match.");
}
} else {
- throw new RuntimeException("Unexpected product_urn: " +
- st.getProductURN());
+ if (!st.getProductURN().equals(jreUrn) ||
+ !st.getProductName().equals(
+ props.getProperty("servicetag.jre.name"))) {
+ throw new RuntimeException("Product URN and name don't match.");
+ }
}
+
if (!st.getProductVersion().
equals(System.getProperty("java.version"))) {
throw new RuntimeException("Unexpected product_version: " +
@@ -233,18 +253,13 @@
}
}
- private static Properties loadSwordfishEntries()
+ private static Properties loadServiceTagProps()
throws IOException {
- int version = sun.misc.Version.jdkMinorVersion();
- String filename = "/com/sun/servicetag/resources/javase_" +
- version + "_swordfish.properties";
- InputStream in = Installer.class.getClass().getResourceAsStream(filename);
- Properties props = new Properties();
- try {
+ String filename = "/com/sun/servicetag/resources/javase_servicetag.properties";
+ try (InputStream in = Installer.class.getClass().getResourceAsStream(filename)) {
+ Properties props = new Properties();
props.load(in);
- } finally {
- in.close();
+ return props;
}
- return props;
}
}
--- a/jdk/test/java/lang/invoke/InvokeGenericTest.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/java/lang/invoke/InvokeGenericTest.java Mon Sep 12 16:59:34 2011 -0700
@@ -25,7 +25,7 @@
/* @test
* @summary unit tests for java.lang.invoke.MethodHandle.invoke
- * @compile -target 7 InvokeGenericTest.java
+ * @compile InvokeGenericTest.java
* @run junit/othervm test.java.lang.invoke.InvokeGenericTest
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/TypeVariable/TestAnnotatedElement.java Mon Sep 12 16:59:34 2011 -0700
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7086192
+ * @summary Verify functionality of AnnotatedElement methods on type variables
+ * @author Joseph D. Darcy
+ */
+
+import java.lang.reflect.*;
+import java.lang.annotation.*;
+
+public class TestAnnotatedElement<A> {
+ // Type variable on a method
+ private static <B> B m(B b) {return null;}
+
+ // Type variable on a construtor
+ private <C> TestAnnotatedElement(){super();}
+
+ public static void main(String... argv) throws ReflectiveOperationException {
+ int errors = 0;
+
+ Class<?> clazz = TestAnnotatedElement.class;
+ errors += testTypeVariable(clazz.getTypeParameters());
+ errors += testTypeVariable(clazz.getDeclaredConstructor().getTypeParameters());
+ errors += testTypeVariable(clazz.getDeclaredMethod("m", Object.class).getTypeParameters());
+
+ if (errors > 0)
+ throw new RuntimeException(errors + " failures");
+ }
+
+
+ private static int testTypeVariable(TypeVariable<?>[] typeVars) {
+ int errors = 0;
+ if (typeVars.length == 0)
+ return ++errors;
+
+ for(TypeVariable<?> typeVar : typeVars) {
+ try {
+ typeVar.getAnnotation(null);
+ errors++;
+ } catch(NullPointerException npe) {
+ ; // Expected
+ }
+
+ if (typeVar.getAnnotation(SuppressWarnings.class) != null)
+ errors++;
+
+ try {
+ typeVar.isAnnotationPresent(null);
+ errors++;
+ } catch(NullPointerException npe) {
+ ; // Expected
+ }
+
+ if (typeVar.isAnnotationPresent(SuppressWarnings.class))
+ errors++;
+
+ if(typeVar.getAnnotations().length != 0)
+ errors++;
+
+ if(typeVar.getDeclaredAnnotations().length != 0)
+ errors++;
+ }
+ return errors;
+ }
+}
--- a/jdk/test/java/math/BigDecimal/DivideMcTests.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/java/math/BigDecimal/DivideMcTests.java Mon Sep 12 16:59:34 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
--- a/jdk/test/java/math/BigDecimal/FloatDoubleValueTests.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/java/math/BigDecimal/FloatDoubleValueTests.java Mon Sep 12 16:59:34 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2011 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 6274390
+ * @bug 6274390 7082971
* @summary Verify {float, double}Value methods work with condensed representation
* @run main FloatDoubleValueTests
* @run main/othervm -XX:+AggressiveOpts FloatDoubleValueTests
@@ -79,6 +79,7 @@
// and double.
static void testFloatDoubleValue() {
long longValues[] = {
+ Long.MIN_VALUE, // -2^63
0,
1,
2,
--- a/jdk/test/java/math/BigDecimal/RangeTests.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/java/math/BigDecimal/RangeTests.java Mon Sep 12 16:59:34 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
--- a/jdk/test/java/math/BigDecimal/StrippingZerosTest.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/java/math/BigDecimal/StrippingZerosTest.java Mon Sep 12 16:59:34 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2011 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
--- a/jdk/test/java/math/BigDecimal/ToPlainStringTests.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/java/math/BigDecimal/ToPlainStringTests.java Mon Sep 12 16:59:34 2011 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/Socket/ShutdownInput.java Mon Sep 12 16:59:34 2011 -0700
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7014860
+ * @summary Socket.getInputStream().available() not clear for
+ * case that connection is shutdown for reading
+ */
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+
+public class ShutdownInput {
+ static boolean failed = false;
+
+ public static void main(String args[]) throws Exception {
+ InetAddress iaddr = InetAddress.getLocalHost();
+
+ try ( ServerSocket ss = new ServerSocket(0);
+ Socket s1 = new Socket(iaddr, ss.getLocalPort());
+ Socket s2 = ss.accept() ) {
+
+ test(s1, s2, "Testing NET");
+ }
+
+ // check the NIO socket adapter
+ try (ServerSocketChannel sc = ServerSocketChannel.open().bind(null);
+ SocketChannel s1 = SocketChannel.open(
+ new InetSocketAddress(iaddr, sc.socket().getLocalPort()));
+ SocketChannel s2 = sc.accept() ) {
+
+ test(s1.socket(), s2.socket(), "Testing NIO");
+ }
+
+ if (failed) {
+ throw new RuntimeException("Failed: check output");
+ }
+ }
+
+ public static void test(Socket s1, Socket s2, String mesg) throws Exception {
+ OutputStream os = s1.getOutputStream();
+ os.write("This is a message".getBytes("US-ASCII"));
+
+ InputStream in = s2.getInputStream();
+ s2.shutdownInput();
+
+ if (in.available() != 0) {
+ failed = true;
+ System.out.println(mesg + ":" + s2 + " in.available() should be 0, " +
+ "but returns "+ in.available());
+ }
+
+ byte[] ba = new byte[2];
+ if (in.read() != -1 ||
+ in.read(ba) != -1 ||
+ in.read(ba, 0, ba.length) != -1) {
+
+ failed = true;
+ System.out.append(mesg + ":" + s2 + " in.read() should be -1");
+ }
+ }
+}
--- a/jdk/test/java/net/URI/Test.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/java/net/URI/Test.java Mon Sep 12 16:59:34 2011 -0700
@@ -23,7 +23,7 @@
/* @test
* @summary Unit test for java.net.URI
- * @bug 4464135 4505046 4503239 4438319 4991359 4866303 7023363
+ * @bug 4464135 4505046 4503239 4438319 4991359 4866303 7023363 7041800
* @author Mark Reinhold
*/
@@ -1428,6 +1428,8 @@
gt(s, new URI("http://jag:CafeBabe@java.sun.com:94/b/c/d?q#f"));
lt(s, new URI("http://jag:cafebabe@java.sun.com:94/b/c/d?r#f"));
lt(s, new URI("http://jag:cafebabe@java.sun.com:94/b/c/d?q#g"));
+ eq(new URI("http://host/a%00bcd"), new URI("http://host/a%00bcd"));
+ ne(new URI("http://host/a%00bcd"), new URI("http://host/aZ00bcd"));
lt("p", "s:p");
lt("s:p", "T:p");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/security/KeyPairGenerator/SolarisShortDSA.java Mon Sep 12 16:59:34 2011 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7081411
+ * @summary DSA keypair generation affected by Solaris bug
+ */
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Signature;
+import sun.security.provider.DSAPrivateKey;
+
+public class SolarisShortDSA {
+ static byte[] data = new byte[0];
+ public static void main(String args[]) throws Exception {
+ for (int i=0; i<10000; i++) {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
+ KeyPair kp = kpg.generateKeyPair();
+ DSAPrivateKey dpk = (DSAPrivateKey)kp.getPrivate();
+ int len = dpk.getX().bitLength();
+ if (len <= 152) {
+ if (!use(kp)) {
+ String os = System.getProperty("os.name");
+ // Solaris bug, update the following line once it's fixed
+ if (os.equals("SunOS")) {
+ throw new IllegalStateException(
+ "Don't panic. This is a Solaris bug");
+ } else {
+ throw new RuntimeException("Real test failure");
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ static boolean use(KeyPair kp) throws Exception {
+ Signature sig = Signature.getInstance("SHA1withDSA");
+ sig.initSign(kp.getPrivate());
+ sig.update(data);
+ byte[] signed = sig.sign();
+ Signature sig2 = Signature.getInstance("SHA1withDSA");
+ sig2.initVerify(kp.getPublic());
+ sig2.update(data);
+ return sig2.verify(signed);
+ }
+}
--- a/jdk/test/javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java Mon Sep 12 16:59:34 2011 -0700
@@ -26,6 +26,7 @@
* @bug 6436919 6460930
* @summary check that XML Signatures can be generated and validated with
* SecurityManager enabled and default policy
+ * @run main/othervm XMLDSigWithSecMgr
* @author Sean Mullan
*/
import java.io.*;
--- a/jdk/test/lib/security/java.policy/Ext_AllPolicy.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/lib/security/java.policy/Ext_AllPolicy.sh Mon Sep 12 16:59:34 2011 -0700
@@ -54,19 +54,16 @@
NULL=/dev/null
PS=":"
FS="/"
- TMP=/tmp
;;
CYGWIN* )
NULL=/dev/null
PS=";"
FS="/"
- TMP=/tmp
;;
Windows_95 | Windows_98 | Windows_NT )
NULL=NUL
PS=";"
FS="\\"
- TMP="c:/temp"
;;
* )
echo "Unrecognized system!"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/DupEtypes.java Mon Sep 12 16:59:34 2011 -0700
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7067974
+ * @summary multiple ETYPE-INFO-ENTRY with same etype and different salt
+ * @compile -XDignore.symbol.file DupEtypes.java
+ * @run main/othervm DupEtypes 1
+ * @run main/othervm DupEtypes 2
+ * @run main/othervm/fail DupEtypes 3
+ * @run main/othervm DupEtypes 4
+ * @run main/othervm DupEtypes 5
+ */
+
+import sun.security.jgss.GSSUtil;
+
+public class DupEtypes {
+
+ public static void main(String[] args) throws Exception {
+
+ OneKDC kdc = new OneKDC(null);
+ kdc.writeJAASConf();
+
+ // Different test cases, read KDC.processAsReq for details
+ kdc.setOption(KDC.Option.DUP_ETYPE, Integer.parseInt(args[0]));
+
+ Context c, s;
+ c = Context.fromJAAS("client");
+ s = Context.fromJAAS("server");
+
+ c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
+ s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
+
+ Context.handshake(c, s);
+
+ Context.transmit("i say high --", c, s);
+ Context.transmit(" you say low", s, c);
+
+ s.dispose();
+ c.dispose();
+ }
+}
--- a/jdk/test/sun/security/krb5/auto/KDC.java Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/krb5/auto/KDC.java Mon Sep 12 16:59:34 2011 -0700
@@ -174,6 +174,10 @@
* Set all name-type to a value in response
*/
RESP_NT,
+ /**
+ * Multiple ETYPE-INFO-ENTRY with same etype but different salt
+ */
+ DUP_ETYPE,
};
static {
@@ -881,48 +885,104 @@
bFlags[Krb5.TKT_OPTS_INITIAL] = true;
// Creating PA-DATA
- int[] epas = eTypes;
- if (options.containsKey(KDC.Option.RC4_FIRST_PREAUTH)) {
- for (int i=1; i<epas.length; i++) {
- if (epas[i] == EncryptedData.ETYPE_ARCFOUR_HMAC) {
- epas[i] = epas[0];
- epas[0] = EncryptedData.ETYPE_ARCFOUR_HMAC;
+ DerValue[] pas2 = null, pas = null;
+ if (options.containsKey(KDC.Option.DUP_ETYPE)) {
+ int n = (Integer)options.get(KDC.Option.DUP_ETYPE);
+ switch (n) {
+ case 1: // customer's case in 7067974
+ pas2 = new DerValue[] {
+ new DerValue(new ETypeInfo2(1, null, null).asn1Encode()),
+ new DerValue(new ETypeInfo2(1, "", null).asn1Encode()),
+ new DerValue(new ETypeInfo2(1, OneKDC.REALM, new byte[]{1}).asn1Encode()),
+ };
+ pas = new DerValue[] {
+ new DerValue(new ETypeInfo(1, null).asn1Encode()),
+ new DerValue(new ETypeInfo(1, "").asn1Encode()),
+ new DerValue(new ETypeInfo(1, OneKDC.REALM).asn1Encode()),
+ };
+ break;
+ case 2: // we still reject non-null s2kparams and prefer E2 over E
+ pas2 = new DerValue[] {
+ new DerValue(new ETypeInfo2(1, OneKDC.REALM, new byte[]{1}).asn1Encode()),
+ new DerValue(new ETypeInfo2(1, null, null).asn1Encode()),
+ new DerValue(new ETypeInfo2(1, "", null).asn1Encode()),
+ };
+ pas = new DerValue[] {
+ new DerValue(new ETypeInfo(1, OneKDC.REALM).asn1Encode()),
+ new DerValue(new ETypeInfo(1, null).asn1Encode()),
+ new DerValue(new ETypeInfo(1, "").asn1Encode()),
+ };
+ break;
+ case 3: // but only E is wrong
+ pas = new DerValue[] {
+ new DerValue(new ETypeInfo(1, OneKDC.REALM).asn1Encode()),
+ new DerValue(new ETypeInfo(1, null).asn1Encode()),
+ new DerValue(new ETypeInfo(1, "").asn1Encode()),
+ };
+ break;
+ case 4: // we also ignore rc4-hmac
+ pas = new DerValue[] {
+ new DerValue(new ETypeInfo(23, "ANYTHING").asn1Encode()),
+ new DerValue(new ETypeInfo(1, null).asn1Encode()),
+ new DerValue(new ETypeInfo(1, "").asn1Encode()),
+ };
+ break;
+ case 5: // "" should be wrong, but we accept it now
+ // See s.s.k.internal.PAData$SaltAndParams
+ pas = new DerValue[] {
+ new DerValue(new ETypeInfo(1, "").asn1Encode()),
+ new DerValue(new ETypeInfo(1, null).asn1Encode()),
+ };
+ break;
+ }
+ } else {
+ int[] epas = eTypes;
+ if (options.containsKey(KDC.Option.RC4_FIRST_PREAUTH)) {
+ for (int i=1; i<epas.length; i++) {
+ if (epas[i] == EncryptedData.ETYPE_ARCFOUR_HMAC) {
+ epas[i] = epas[0];
+ epas[0] = EncryptedData.ETYPE_ARCFOUR_HMAC;
+ break;
+ }
+ };
+ } else if (options.containsKey(KDC.Option.ONLY_ONE_PREAUTH)) {
+ epas = new int[] { eTypes[0] };
+ }
+ pas2 = new DerValue[epas.length];
+ for (int i=0; i<epas.length; i++) {
+ pas2[i] = new DerValue(new ETypeInfo2(
+ epas[i],
+ epas[i] == EncryptedData.ETYPE_ARCFOUR_HMAC ?
+ null : getSalt(body.cname),
+ null).asn1Encode());
+ }
+ boolean allOld = true;
+ for (int i: eTypes) {
+ if (i == EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96 ||
+ i == EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96) {
+ allOld = false;
break;
}
- };
- } else if (options.containsKey(KDC.Option.ONLY_ONE_PREAUTH)) {
- epas = new int[] { eTypes[0] };
+ }
+ if (allOld) {
+ pas = new DerValue[epas.length];
+ for (int i=0; i<epas.length; i++) {
+ pas[i] = new DerValue(new ETypeInfo(
+ epas[i],
+ epas[i] == EncryptedData.ETYPE_ARCFOUR_HMAC ?
+ null : getSalt(body.cname)
+ ).asn1Encode());
+ }
+ }
}
- DerValue[] pas = new DerValue[epas.length];
- for (int i=0; i<epas.length; i++) {
- pas[i] = new DerValue(new ETypeInfo2(
- epas[i],
- epas[i] == EncryptedData.ETYPE_ARCFOUR_HMAC ?
- null : getSalt(body.cname),
- null).asn1Encode());
+ DerOutputStream eid;
+ if (pas2 != null) {
+ eid = new DerOutputStream();
+ eid.putSequence(pas2);
+ outPAs.add(new PAData(Krb5.PA_ETYPE_INFO2, eid.toByteArray()));
}
- DerOutputStream eid = new DerOutputStream();
- eid.putSequence(pas);
-
- outPAs.add(new PAData(Krb5.PA_ETYPE_INFO2, eid.toByteArray()));
-
- boolean allOld = true;
- for (int i: eTypes) {
- if (i == EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96 ||
- i == EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96) {
- allOld = false;
- break;
- }
- }
- if (allOld) {
- for (int i=0; i<epas.length; i++) {
- pas[i] = new DerValue(new ETypeInfo(
- epas[i],
- epas[i] == EncryptedData.ETYPE_ARCFOUR_HMAC ?
- null : getSalt(body.cname)
- ).asn1Encode());
- }
+ if (pas != null) {
eid = new DerOutputStream();
eid.putSequence(pas);
outPAs.add(new PAData(Krb5.PA_ETYPE_INFO, eid.toByteArray()));
--- a/jdk/test/sun/security/tools/jarsigner/AlgOptions.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/jarsigner/AlgOptions.sh Mon Sep 12 16:59:34 2011 -0700
@@ -51,21 +51,18 @@
PS=":"
FS="/"
CP="${FS}bin${FS}cp -f"
- TMP=/tmp
;;
CYGWIN* )
NULL=/dev/null
PS=";"
FS="/"
CP="cp -f"
- TMP=/tmp
;;
Windows_* )
NULL=NUL
PS=";"
FS="\\"
CP="cp -f"
- TMP="c:/temp"
;;
* )
echo "Unrecognized operating system!"
--- a/jdk/test/sun/security/tools/jarsigner/PercentSign.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/jarsigner/PercentSign.sh Mon Sep 12 16:59:34 2011 -0700
@@ -51,21 +51,18 @@
PS=":"
FS="/"
CP="${FS}bin${FS}cp -f"
- TMP=/tmp
;;
CYGWIN* )
NULL=/dev/null
PS=";"
FS="/"
CP="cp -f"
- TMP=/tmp
;;
Windows_* )
NULL=NUL
PS=";"
FS="\\"
CP="cp -f"
- TMP="c:/temp"
;;
* )
echo "Unrecognized operating system!"
--- a/jdk/test/sun/security/tools/jarsigner/diffend.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/jarsigner/diffend.sh Mon Sep 12 16:59:34 2011 -0700
@@ -46,21 +46,18 @@
PS=":"
FS="/"
CP="${FS}bin${FS}cp -f"
- TMP=/tmp
;;
CYGWIN* )
NULL=/dev/null
PS=";"
FS="/"
CP="cp -f"
- TMP=/tmp
;;
Windows_* )
NULL=NUL
PS=";"
FS="\\"
CP="cp -f"
- TMP="c:/temp"
;;
* )
echo "Unrecognized operating system!"
--- a/jdk/test/sun/security/tools/jarsigner/oldsig.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/jarsigner/oldsig.sh Mon Sep 12 16:59:34 2011 -0700
@@ -47,21 +47,18 @@
PS=":"
FS="/"
CP="${FS}bin${FS}cp -f"
- TMP=/tmp
;;
CYGWIN* )
NULL=/dev/null
PS=";"
FS="/"
CP="cp -f"
- TMP=/tmp
;;
Windows_* )
NULL=NUL
PS=";"
FS="\\"
CP="cp -f"
- TMP="c:/temp"
;;
* )
echo "Unrecognized operating system!"
--- a/jdk/test/sun/security/tools/keytool/AltProviderPath.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/keytool/AltProviderPath.sh Mon Sep 12 16:59:34 2011 -0700
@@ -50,19 +50,16 @@
NULL=/dev/null
PS=":"
FS="/"
- TMP=/tmp
;;
CYGWIN* )
NULL=/dev/null
PS=";"
FS="/"
- TMP=/tmp
;;
Windows_* )
NULL=NUL
PS=";"
FS="\\"
- TMP="c:/temp"
;;
* )
echo "Unrecognized operating system!"
--- a/jdk/test/sun/security/tools/keytool/SecretKeyKS.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/keytool/SecretKeyKS.sh Mon Sep 12 16:59:34 2011 -0700
@@ -49,19 +49,16 @@
NULL=/dev/null
PS=":"
FS="/"
- TMP=/tmp
;;
CYGWIN* )
NULL=/dev/null
PS=";"
FS="/"
- TMP=/tmp
;;
Windows_* )
NULL=NUL
PS=";"
FS="\\"
- TMP="c:/temp"
;;
* )
echo "Unrecognized operating system!"
--- a/jdk/test/sun/security/tools/keytool/StandardAlgName.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/keytool/StandardAlgName.sh Mon Sep 12 16:59:34 2011 -0700
@@ -50,19 +50,16 @@
NULL=/dev/null
PS=":"
FS="/"
- TMP=/tmp
;;
CYGWIN* )
NULL=/dev/null
PS=";"
FS="/"
- TMP=/tmp
;;
Windows_* )
NULL=NUL
PS=";"
FS="\\"
- TMP="c:/temp"
;;
* )
echo "Unrecognized operating system!"
--- a/jdk/test/sun/security/tools/keytool/i18n.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/keytool/i18n.sh Mon Sep 12 16:59:34 2011 -0700
@@ -50,19 +50,16 @@
NULL=/dev/null
PS=":"
FS="/"
- TMP=/tmp
;;
CYGWIN* )
NULL=/dev/null
PS=";"
FS="/"
- TMP=/tmp
;;
Windows* )
NULL=NUL
PS=";"
FS="\\"
- TMP="c:/temp"
;;
* )
echo "Unrecognized system!"
--- a/jdk/test/sun/security/tools/keytool/resource.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/keytool/resource.sh Mon Sep 12 16:59:34 2011 -0700
@@ -46,17 +46,14 @@
SunOS | Linux )
NULL=/dev/null
FS="/"
- TMP=/tmp
;;
CYGWIN* )
NULL=/dev/null
FS="/"
- TMP=/tmp
;;
Windows_* )
NULL=NUL
FS="\\"
- TMP="c:/temp"
;;
* )
echo "Unrecognized operating system!"
@@ -65,13 +62,11 @@
esac
# the test code
-${TESTJAVA}${FS}bin${FS}keytool > ${TMP}${FS}temp_file_40875602475 2> ${NULL}
-grep MissingResourceException ${TMP}${FS}temp_file_40875602475
+${TESTJAVA}${FS}bin${FS}keytool > temp_file_40875602475 2> ${NULL}
+grep MissingResourceException temp_file_40875602475
if [ $? -eq 0 ]; then
- rm ${TMP}${FS}temp_file_40875602475
exit 1
fi
-rm ${TMP}${FS}temp_file_40875602475
exit 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/tools/keytool/trystore.sh Mon Sep 12 16:59:34 2011 -0700
@@ -0,0 +1,65 @@
+#
+# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @bug 7047200
+# @summary keytool can try save to a byte array before overwrite the file
+
+if [ "${TESTJAVA}" = "" ] ; then
+ JAVAC_CMD=`which javac`
+ TESTJAVA=`dirname $JAVAC_CMD`/..
+fi
+
+# set platform-dependent variables
+OS=`uname -s`
+case "$OS" in
+ Windows_* )
+ FS="\\"
+ ;;
+ * )
+ FS="/"
+ ;;
+esac
+
+rm trystore.jks 2> /dev/null
+
+KEYTOOL="${TESTJAVA}${FS}bin${FS}keytool -storetype jks -keystore trystore.jks"
+$KEYTOOL -genkeypair -alias a -dname CN=A -storepass changeit -keypass changeit
+$KEYTOOL -genkeypair -alias b -dname CN=B -storepass changeit -keypass changeit
+
+# We use -protected for JKS keystore. This is illegal so the command should
+# fail. Then we can check if the keystore is damaged.
+
+$KEYTOOL -genkeypair -protected -alias b -delete -debug
+
+if [ $? = 0 ]; then
+ echo "What? -protected works for JKS?"
+ exit 1
+fi
+
+$KEYTOOL -list -storepass changeit
+
+if [ $? != 0 ]; then
+ echo "Keystore file damaged"
+ exit 2
+fi
--- a/jdk/test/sun/security/tools/policytool/Alias.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/policytool/Alias.sh Mon Sep 12 16:59:34 2011 -0700
@@ -51,13 +51,11 @@
NULL=/dev/null
PS=":"
FS="/"
- TMP=/tmp
;;
Windows* )
NULL=NUL
PS=";"
FS="\\"
- TMP="c:/temp"
;;
* )
echo "Unrecognized system!"
--- a/jdk/test/sun/security/tools/policytool/ChangeUI.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/policytool/ChangeUI.sh Mon Sep 12 16:59:34 2011 -0700
@@ -50,13 +50,11 @@
NULL=/dev/null
PS=":"
FS="/"
- TMP=/tmp
;;
Windows* )
NULL=NUL
PS=";"
FS="\\"
- TMP="c:/temp"
;;
* )
echo "Unrecognized system!"
--- a/jdk/test/sun/security/tools/policytool/OpenPolicy.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/policytool/OpenPolicy.sh Mon Sep 12 16:59:34 2011 -0700
@@ -50,13 +50,11 @@
NULL=/dev/null
PS=":"
FS="/"
- TMP=/tmp
;;
Windows* )
NULL=NUL
PS=";"
FS="\\"
- TMP="c:/temp"
;;
* )
echo "Unrecognized system!"
--- a/jdk/test/sun/security/tools/policytool/SaveAs.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/policytool/SaveAs.sh Mon Sep 12 16:59:34 2011 -0700
@@ -51,13 +51,11 @@
NULL=/dev/null
PS=":"
FS="/"
- TMP=/tmp
;;
Windows* )
NULL=NUL
PS=";"
FS="\\"
- TMP="c:/temp"
;;
* )
echo "Unrecognized system!"
--- a/jdk/test/sun/security/tools/policytool/UpdatePermissions.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/policytool/UpdatePermissions.sh Mon Sep 12 16:59:34 2011 -0700
@@ -50,13 +50,11 @@
NULL=/dev/null
PS=":"
FS="/"
- TMP=/tmp
;;
Windows* )
NULL=NUL
PS=";"
FS="\\"
- TMP="c:/temp"
;;
* )
echo "Unrecognized system!"
--- a/jdk/test/sun/security/tools/policytool/UsePolicy.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/policytool/UsePolicy.sh Mon Sep 12 16:59:34 2011 -0700
@@ -50,13 +50,11 @@
NULL=/dev/null
PS=":"
FS="/"
- TMP=/tmp
;;
Windows* )
NULL=NUL
PS=";"
FS="\\"
- TMP="c:/temp"
;;
* )
echo "Unrecognized system!"
--- a/jdk/test/sun/security/tools/policytool/i18n.sh Mon Sep 12 15:49:08 2011 -0700
+++ b/jdk/test/sun/security/tools/policytool/i18n.sh Mon Sep 12 16:59:34 2011 -0700
@@ -50,13 +50,11 @@
NULL=/dev/null
PS=":"
FS="/"
- TMP=/tmp
;;
Windows* )
NULL=NUL
PS=";"
FS="\\"
- TMP="c:/temp"
;;
* )
echo "Unrecognized system!"