--- old/src/share/classes/java/lang/ArithmeticException.java 2011-03-29 18:45:36.000000000 -0700 +++ new/src/share/classes/java/lang/ArithmeticException.java 2011-03-29 18:45:36.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -30,15 +30,18 @@ * example, an integer "divide by zero" throws an * instance of this class. * + * {@code ArithmeticException} objects may be constructed by the + * virtual machine as if {@linkplain Throwable#(String, Throwable, + * boolean) suppression were disabled}. + * * @author unascribed * @since JDK1.0 */ -public -class ArithmeticException extends RuntimeException { +public class ArithmeticException extends RuntimeException { private static final long serialVersionUID = 2256477558314496007L; /** - * Constructs an ArithmeticException with no detail + * Constructs an {@code ArithmeticException} with no detail * message. */ public ArithmeticException() { @@ -46,7 +49,7 @@ } /** - * Constructs an ArithmeticException with the specified + * Constructs an {@code ArithmeticException} with the specified * detail message. * * @param s the detail message. --- old/src/share/classes/java/lang/NullPointerException.java 2011-03-29 18:45:37.000000000 -0700 +++ new/src/share/classes/java/lang/NullPointerException.java 2011-03-29 18:45:37.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -26,20 +26,24 @@ package java.lang; /** - * Thrown when an application attempts to use null in a + * Thrown when an application attempts to use {@code null} in a * case where an object is required. These include: * *

* Applications should throw instances of this class to indicate - * other illegal uses of the null object. + * other illegal uses of the {@code null} object. + * + * {@code NullPointerException} objects may be constructed by the + * virtual machine as if {@linkplain Throwable#(String, Throwable, + * boolean) suppression were disabled}. * * @author unascribed * @since JDK1.0 @@ -49,14 +53,14 @@ private static final long serialVersionUID = 5162710183389028792L; /** - * Constructs a NullPointerException with no detail message. + * Constructs a {@code NullPointerException} with no detail message. */ public NullPointerException() { super(); } /** - * Constructs a NullPointerException with the specified + * Constructs a {@code NullPointerException} with the specified * detail message. * * @param s the detail message. --- old/src/share/classes/java/lang/OutOfMemoryError.java 2011-03-29 18:45:37.000000000 -0700 +++ new/src/share/classes/java/lang/OutOfMemoryError.java 2011-03-29 18:45:37.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -30,22 +30,25 @@ * because it is out of memory, and no more memory could be made * available by the garbage collector. * + * {@code OutOfMemoryError} objects may be constructed by the virtual + * machine as if {@linkplain Throwable#(String, Throwable, boolean) + * suppression were disabled}. + * * @author unascribed * @since JDK1.0 */ -public -class OutOfMemoryError extends VirtualMachineError { +public class OutOfMemoryError extends VirtualMachineError { private static final long serialVersionUID = 8228564086184010517L; /** - * Constructs an OutOfMemoryError with no detail message. + * Constructs an {@code OutOfMemoryError} with no detail message. */ public OutOfMemoryError() { super(); } /** - * Constructs an OutOfMemoryError with the specified + * Constructs an {@code OutOfMemoryError} with the specified * detail message. * * @param s the detail message. --- old/src/share/classes/java/lang/Throwable.java 2011-03-29 18:45:38.000000000 -0700 +++ new/src/share/classes/java/lang/Throwable.java 2011-03-29 18:45:38.000000000 -0700 @@ -283,6 +283,41 @@ } /** + * Constructs a new throwable with the specified detail message, + * cause, and {@linkplain #addSuppressed suppression} enabled or + * disabled. If suppression is disabled, {@link #getSuppressed} + * for this object will return a zero-length array and calls to + * {@link #addSuppressed} that would otherwise append an exception + * to the suppressed list will have no effect. + * + *

Note that the other constructors of {@code Throwable} treat + * suppression as being enabled. Subclasses of {@code Throwable} + * should document any conditions under which suppression is + * disabled. Disabling of suppression should only occur in + * exceptional circumstances where special requirements exist, + * such as a virtual machine reusing exception objects under + * low-memory situations. + * + * @param message the detail message. + * @param cause the cause. (A {@code null} value is permitted, + * and indicates that the cause is nonexistent or unknown.) + * @param enableSuppression whether or not suppression is enabled or disabled + * + * @see OutOfMemoryError + * @see NullPointerException + * @see ArithmeticException + * @since 1.7 + */ + protected Throwable(String message, Throwable cause, + boolean enableSuppression) { + fillInStackTrace(); + detailMessage = message; + this.cause = cause; + if (!enableSuppression) + suppressedExceptions = null; + } + + /** * Returns the detail message string of this throwable. * * @return the detail message string of this {@code Throwable} instance @@ -830,13 +865,10 @@ * typically called (automatically and implicitly) by the {@code * try}-with-resources statement. * - * If the first exception to be suppressed is {@code null}, that - * indicates suppressed exception information will not be - * recorded for this exception. Subsequent calls to this method - * will not record any suppressed exceptions. Otherwise, - * attempting to suppress {@code null} after an exception has - * already been successfully suppressed results in a {@code - * NullPointerException}. + *

The suppression behavior is enabled unless disabled + * {@linkplain #Throwable(String, Throwable, boolean) via a + * constructor}. When suppression is disabled, this method does + * nothing other than to validate its argument. * *

Note that when one exception {@linkplain * #initCause(Throwable) causes} another exception, the first @@ -874,31 +906,22 @@ * suppressed exceptions * @throws IllegalArgumentException if {@code exception} is this * throwable; a throwable cannot suppress itself. - * @throws NullPointerException if {@code exception} is null and - * an exception has already been suppressed by this exception + * @throws NullPointerException if {@code exception} is {@code null} * @since 1.7 */ public final synchronized void addSuppressed(Throwable exception) { if (exception == this) throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE); - if (exception == null) { - if (suppressedExceptions == SUPPRESSED_SENTINEL) { - suppressedExceptions = null; // No suppression information recorded - return; - } else - throw new NullPointerException(NULL_CAUSE_MESSAGE); - } else { - assert exception != null && exception != this; - - if (suppressedExceptions == null) // Suppressed exceptions not recorded - return; - - if (suppressedExceptions == SUPPRESSED_SENTINEL) - suppressedExceptions = new ArrayList<>(1); + if (exception == null) + throw new NullPointerException(NULL_CAUSE_MESSAGE); - assert suppressedExceptions != SUPPRESSED_SENTINEL; + if (suppressedExceptions == null) // Suppressed exceptions not recorded + return; + if (suppressedExceptions == SUPPRESSED_SENTINEL) { + suppressedExceptions = new ArrayList<>(1); + suppressedExceptions.add(exception); } } @@ -910,7 +933,9 @@ * suppressed, typically by the {@code try}-with-resources * statement, in order to deliver this exception. * - * If no exceptions were suppressed, an empty array is returned. + * If no exceptions were suppressed or {@linkplain + * Throwable(String, Throwable, boolean) suppression is disabled}, + * an empty array is returned. * * @return an array containing all of the exceptions that were * suppressed to deliver this exception. --- old/test/java/lang/Throwable/SuppressedExceptions.java 2011-03-29 18:45:38.000000000 -0700 +++ new/test/java/lang/Throwable/SuppressedExceptions.java 2011-03-29 18:45:38.000000000 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -26,7 +26,7 @@ /* * @test - * @bug 6911258 6962571 6963622 6991528 + * @bug 6911258 6962571 6963622 6991528 7005628 * @summary Basic tests of suppressed exceptions * @author Joseph D. Darcy */ @@ -50,14 +50,6 @@ } catch (IllegalArgumentException iae) { ; // Expected } - - throwable.addSuppressed(null); // Immutable suppression list - try { - throwable.addSuppressed(throwable); - throw new RuntimeException("IllegalArgumentException for self-suppresion not thrown."); - } catch (IllegalArgumentException iae) { - ; // Expected - } } private static void basicSupressionTest() { @@ -183,8 +175,7 @@ } private static void noModification() { - Throwable t = new Throwable(); - t.addSuppressed(null); + Throwable t = new NoSuppression(false); Throwable[] t0 = t.getSuppressed(); if (t0.length != 0) @@ -196,5 +187,24 @@ t0 = t.getSuppressed(); if (t0.length != 0) throw new RuntimeException("Bad nonzero length of suppressed exceptions."); + + Throwable suppressed = new ArithmeticException(); + t = new NoSuppression(true); // Suppression enabled + // Make sure addSuppressed(null) throws an NPE + try { + t.addSuppressed(null); + } catch(NullPointerException e) { + ; // Expected + } + t.addSuppressed(suppressed); + t0 = t.getSuppressed(); + if (t0.length != 1 || t0[0] != suppressed) + throw new RuntimeException("Expected suppression did not occur."); + } + + private static class NoSuppression extends Throwable { + public NoSuppression(boolean enableSuppression) { + super("The medium.", null, enableSuppression); + } } }