8198249: Remove deprecated Runtime::runFinalizersOnExit and System::runFinalizersOnExit
authormchung
Fri, 23 Feb 2018 12:10:56 -0800
changeset 48942 a6c4b85163c1
parent 48941 4f11514fe783
child 48943 e61816fc5276
8198249: Remove deprecated Runtime::runFinalizersOnExit and System::runFinalizersOnExit Reviewed-by: dholmes, alanb, smarks
make/mapfiles/libjava/mapfile-vers
src/hotspot/share/classfile/vmSymbols.hpp
src/hotspot/share/memory/universe.cpp
src/hotspot/share/memory/universe.hpp
src/hotspot/share/runtime/thread.cpp
src/java.base/share/classes/java/lang/Runtime.java
src/java.base/share/classes/java/lang/Shutdown.java
src/java.base/share/classes/java/lang/System.java
src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html
src/java.base/share/classes/java/lang/ref/Finalizer.java
src/java.base/share/classes/jdk/internal/misc/VM.java
src/java.base/share/native/libjava/Shutdown.c
src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java
src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/internals.md
src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md
test/hotspot/jtreg/testlibrary/jittester/conf/exclude.methods.lst
test/jdk/java/lang/Runtime/shutdown/Basic.java
test/jdk/java/lang/System/ExitFinalizersAndJIT.java
test/jdk/java/lang/System/finalization/FinExit.java
test/jdk/java/lang/System/finalization/FinExit.sh
--- a/make/mapfiles/libjava/mapfile-vers	Fri Feb 23 14:26:29 2018 -0500
+++ b/make/mapfiles/libjava/mapfile-vers	Fri Feb 23 12:10:56 2018 -0800
@@ -143,7 +143,6 @@
                 Java_java_lang_StackStreamFactory_checkStackWalkModes;
                 Java_java_lang_StackStreamFactory_00024AbstractStackWalker_callStackWalk;
                 Java_java_lang_StackStreamFactory_00024AbstractStackWalker_fetchStackFrames;
-		Java_java_lang_Shutdown_runAllFinalizers;
 		Java_java_lang_StrictMath_IEEEremainder;
 		Java_java_lang_StrictMath_acos;
 		Java_java_lang_StrictMath_asin;
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Fri Feb 23 12:10:56 2018 -0800
@@ -358,7 +358,6 @@
   template(reference_lock_name,                       "lock")                                     \
   template(reference_discovered_name,                 "discovered")                               \
   template(run_finalization_name,                     "runFinalization")                          \
-  template(run_finalizers_on_exit_name,               "runFinalizersOnExit")                      \
   template(dispatchUncaughtException_name,            "dispatchUncaughtException")                \
   template(loadClass_name,                            "loadClass")                                \
   template(loadClassInternal_name,                    "loadClassInternal")                        \
--- a/src/hotspot/share/memory/universe.cpp	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/hotspot/share/memory/universe.cpp	Fri Feb 23 12:10:56 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, 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
@@ -542,32 +542,6 @@
 #undef assert_pll_locked
 #undef assert_pll_ownership
 
-
-static bool has_run_finalizers_on_exit = false;
-
-void Universe::run_finalizers_on_exit() {
-  if (has_run_finalizers_on_exit) return;
-  has_run_finalizers_on_exit = true;
-
-  // Called on VM exit. This ought to be run in a separate thread.
-  log_trace(ref)("Callback to run finalizers on exit");
-  {
-    PRESERVE_EXCEPTION_MARK;
-    Klass* finalizer_klass = SystemDictionary::Finalizer_klass();
-    JavaValue result(T_VOID);
-    JavaCalls::call_static(
-      &result,
-      finalizer_klass,
-      vmSymbols::run_finalizers_on_exit_name(),
-      vmSymbols::void_method_signature(),
-      THREAD
-    );
-    // Ignore any pending exceptions
-    CLEAR_PENDING_EXCEPTION;
-  }
-}
-
-
 // initialize_vtable could cause gc if
 // 1) we specified true to initialize_vtable and
 // 2) this ran after gc was enabled
--- a/src/hotspot/share/memory/universe.hpp	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/hotspot/share/memory/universe.hpp	Fri Feb 23 12:10:56 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, 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
@@ -464,9 +464,6 @@
   static bool        should_fill_in_stack_trace(Handle throwable);
   static void check_alignment(uintx size, uintx alignment, const char* name);
 
-  // Finalizer support.
-  static void run_finalizers_on_exit();
-
   // Iteration
 
   // Apply "f" to the addresses of all the direct heap pointers maintained
--- a/src/hotspot/share/runtime/thread.cpp	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/hotspot/share/runtime/thread.cpp	Fri Feb 23 12:10:56 2018 -0800
@@ -4202,10 +4202,9 @@
     // SystemDictionary::resolve_or_null will return null if there was
     // an exception.  If we cannot load the Shutdown class, just don't
     // call Shutdown.shutdown() at all.  This will mean the shutdown hooks
-    // and finalizers (if runFinalizersOnExit is set) won't be run.
-    // Note that if a shutdown hook was registered or runFinalizersOnExit
-    // was called, the Shutdown class would have already been loaded
-    // (Runtime.addShutdownHook and runFinalizersOnExit will load it).
+    // won't be run.  Note that if a shutdown hook was registered,
+    // the Shutdown class would have already been loaded
+    // (Runtime.addShutdownHook will load it).
     JavaValue result(T_VOID);
     JavaCalls::call_static(&result,
                            shutdown_klass,
@@ -4228,7 +4227,7 @@
 //   + Wait until we are the last non-daemon thread to execute
 //     <-- every thing is still working at this moment -->
 //   + Call java.lang.Shutdown.shutdown(), which will invoke Java level
-//        shutdown hooks, run finalizers if finalization-on-exit
+//        shutdown hooks
 //   + Call before_exit(), prepare for VM exit
 //      > run VM level shutdown hooks (they are registered through JVM_OnExit(),
 //        currently the only user of this mechanism is File.deleteOnExit())
--- a/src/java.base/share/classes/java/lang/Runtime.java	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/java.base/share/classes/java/lang/Runtime.java	Fri Feb 23 12:10:56 2018 -0800
@@ -79,18 +79,14 @@
      * serves as a status code; by convention, a nonzero status code indicates
      * abnormal termination.
      *
-     * <p> The virtual machine's shutdown sequence consists of two phases.  In
-     * the first phase all registered {@link #addShutdownHook shutdown hooks},
-     * if any, are started in some unspecified order and allowed to run
-     * concurrently until they finish.  In the second phase all uninvoked
-     * finalizers are run if {@link #runFinalizersOnExit finalization-on-exit}
-     * has been enabled.  Once this is done the virtual machine {@link #halt halts}.
+     * <p> All registered {@linkplain #addShutdownHook shutdown hooks}, if any,
+     * are started in some unspecified order and allowed to run concurrently
+     * until they finish.  Once this is done the virtual machine
+     * {@linkplain #halt halts}.
      *
-     * <p> If this method is invoked after the virtual machine has begun its
-     * shutdown sequence then if shutdown hooks are being run this method will
-     * block indefinitely.  If shutdown hooks have already been run and on-exit
-     * finalization has been enabled then this method halts the virtual machine
-     * with the given status code if the status is nonzero; otherwise, it
+     * <p> If this method is invoked after all shutdown hooks have already
+     * been run and the status is nonzero then this method halts the
+     * virtual machine with the given status code. Otherwise, this method
      * blocks indefinitely.
      *
      * <p> The {@link System#exit(int) System.exit} method is the
@@ -109,7 +105,6 @@
      * @see java.lang.SecurityManager#checkExit(int)
      * @see #addShutdownHook
      * @see #removeShutdownHook
-     * @see #runFinalizersOnExit
      * @see #halt(int)
      */
     public void exit(int status) {
@@ -142,10 +137,9 @@
      * thread.  When the virtual machine begins its shutdown sequence it will
      * start all registered shutdown hooks in some unspecified order and let
      * them run concurrently.  When all the hooks have finished it will then
-     * run all uninvoked finalizers if finalization-on-exit has been enabled.
-     * Finally, the virtual machine will halt.  Note that daemon threads will
-     * continue to run during the shutdown sequence, as will non-daemon threads
-     * if shutdown was initiated by invoking the {@link #exit exit} method.
+     * halt. Note that daemon threads will continue to run during the shutdown
+     * sequence, as will non-daemon threads if shutdown was initiated by
+     * invoking the {@link #exit exit} method.
      *
      * <p> Once the shutdown sequence has begun it can be stopped only by
      * invoking the {@link #halt halt} method, which forcibly
@@ -255,10 +249,9 @@
      *
      * <p> This method should be used with extreme caution.  Unlike the
      * {@link #exit exit} method, this method does not cause shutdown
-     * hooks to be started and does not run uninvoked finalizers if
-     * finalization-on-exit has been enabled.  If the shutdown sequence has
-     * already been initiated then this method does not wait for any running
-     * shutdown hooks or finalizers to finish their work.
+     * hooks to be started.  If the shutdown sequence has already been
+     * initiated then this method does not wait for any running
+     * shutdown hooks to finish their work.
      *
      * @param  status
      *         Termination status. By convention, a nonzero status code
@@ -286,46 +279,6 @@
     }
 
     /**
-     * Enable or disable finalization on exit; doing so specifies that the
-     * finalizers of all objects that have finalizers that have not yet been
-     * automatically invoked are to be run before the Java runtime exits.
-     * By default, finalization on exit is disabled.
-     *
-     * <p>If there is a security manager,
-     * its {@code checkExit} method is first called
-     * with 0 as its argument to ensure the exit is allowed.
-     * This could result in a SecurityException.
-     *
-     * @param value true to enable finalization on exit, false to disable
-     * @deprecated  This method is inherently unsafe.  It may result in
-     *      finalizers being called on live objects while other threads are
-     *      concurrently manipulating those objects, resulting in erratic
-     *      behavior or deadlock.
-     *      This method is subject to removal in a future version of Java SE.
-     *
-     * @throws  SecurityException
-     *        if a security manager exists and its {@code checkExit}
-     *        method doesn't allow the exit.
-     *
-     * @see     java.lang.Runtime#exit(int)
-     * @see     java.lang.Runtime#gc()
-     * @see     java.lang.SecurityManager#checkExit(int)
-     * @since   1.1
-     */
-    @Deprecated(since="1.2", forRemoval=true)
-    public static void runFinalizersOnExit(boolean value) {
-        SecurityManager security = System.getSecurityManager();
-        if (security != null) {
-            try {
-                security.checkExit(0);
-            } catch (SecurityException e) {
-                throw new SecurityException("runFinalizersOnExit");
-            }
-        }
-        Shutdown.setRunFinalizersOnExit(value);
-    }
-
-    /**
      * Executes the specified string command in a separate process.
      *
      * <p>This is a convenience method.  An invocation of the form
--- a/src/java.base/share/classes/java/lang/Shutdown.java	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/java.base/share/classes/java/lang/Shutdown.java	Fri Feb 23 12:10:56 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, 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,35 +26,33 @@
 package java.lang;
 
 
+import jdk.internal.misc.VM;
+
 /**
  * Package-private utility class containing data structures and logic
  * governing the virtual-machine shutdown sequence.
  *
  * @author   Mark Reinhold
  * @since    1.3
+ *
+ * @see java.io.Console
+ * @see ApplicationShutdownHooks
+ * @see java.io.DeleteOnExitHook
  */
 
 class Shutdown {
 
-    /* Shutdown state */
-    private static final int RUNNING = 0;
-    private static final int HOOKS = 1;
-    private static final int FINALIZERS = 2;
-    private static int state = RUNNING;
-
-    /* Should we run all finalizers upon exit? */
-    private static boolean runFinalizersOnExit = false;
-
     // The system shutdown hooks are registered with a predefined slot.
     // The list of shutdown hooks is as follows:
     // (0) Console restore hook
-    // (1) Application hooks
+    // (1) ApplicationShutdownHooks that invokes all registered application
+    //     shutdown hooks and waits until they finish
     // (2) DeleteOnExit hook
     private static final int MAX_SYSTEM_HOOKS = 10;
     private static final Runnable[] hooks = new Runnable[MAX_SYSTEM_HOOKS];
 
     // the index of the currently running shutdown hook to the hooks array
-    private static int currentRunningHook = 0;
+    private static int currentRunningHook = -1;
 
     /* The preceding static fields are protected by this lock */
     private static class Lock { };
@@ -63,17 +61,9 @@
     /* Lock object for the native halt method */
     private static Object haltLock = new Lock();
 
-    /* Invoked by Runtime.runFinalizersOnExit */
-    static void setRunFinalizersOnExit(boolean run) {
-        synchronized (lock) {
-            runFinalizersOnExit = run;
-        }
-    }
-
-
     /**
-     * Add a new shutdown hook.  Checks the shutdown state and the hook itself,
-     * but does not do any security checks.
+     * Add a new system shutdown hook.  Checks the shutdown state and
+     * the hook itself, but does not do any security checks.
      *
      * The registerShutdownInProgress parameter should be false except
      * registering the DeleteOnExitHook since the first file may
@@ -92,15 +82,18 @@
      *         already passes the given slot
      */
     static void add(int slot, boolean registerShutdownInProgress, Runnable hook) {
+        if (slot < 0 || slot >= MAX_SYSTEM_HOOKS) {
+            throw new IllegalArgumentException("Invalid slot: " + slot);
+        }
         synchronized (lock) {
             if (hooks[slot] != null)
                 throw new InternalError("Shutdown hook at slot " + slot + " already registered");
 
             if (!registerShutdownInProgress) {
-                if (state > RUNNING)
+                if (currentRunningHook >= 0)
                     throw new IllegalStateException("Shutdown in progress");
             } else {
-                if (state > HOOKS || (state == HOOKS && slot <= currentRunningHook))
+                if (VM.isShutdown() || slot <= currentRunningHook)
                     throw new IllegalStateException("Shutdown in progress");
             }
 
@@ -108,9 +101,23 @@
         }
     }
 
-    /* Run all registered shutdown hooks
+    /* Run all system shutdown hooks.
+     *
+     * The system shutdown hooks are run in the thread synchronized on
+     * Shutdown.class.  Other threads calling Runtime::exit, Runtime::halt
+     * or JNI DestroyJavaVM will block indefinitely.
+     *
+     * ApplicationShutdownHooks is registered as one single hook that starts
+     * all application shutdown hooks and waits until they finish.
      */
     private static void runHooks() {
+        synchronized (lock) {
+            /* Guard against the possibility of a daemon thread invoking exit
+             * after DestroyJavaVM initiates the shutdown sequence
+             */
+            if (VM.isShutdown()) return;
+        }
+
         for (int i=0; i < MAX_SYSTEM_HOOKS; i++) {
             try {
                 Runnable hook;
@@ -121,13 +128,16 @@
                     hook = hooks[i];
                 }
                 if (hook != null) hook.run();
-            } catch(Throwable t) {
+            } catch (Throwable t) {
                 if (t instanceof ThreadDeath) {
                     ThreadDeath td = (ThreadDeath)t;
                     throw td;
                 }
             }
         }
+
+        // set shutdown state
+        VM.shutdown();
     }
 
     /* The halt method is synchronized on the halt lock
@@ -142,74 +152,22 @@
 
     static native void halt0(int status);
 
-    /* Wormhole for invoking java.lang.ref.Finalizer.runAllFinalizers */
-    private static native void runAllFinalizers();
-
-
-    /* The actual shutdown sequence is defined here.
-     *
-     * If it weren't for runFinalizersOnExit, this would be simple -- we'd just
-     * run the hooks and then halt.  Instead we need to keep track of whether
-     * we're running hooks or finalizers.  In the latter case a finalizer could
-     * invoke exit(1) to cause immediate termination, while in the former case
-     * any further invocations of exit(n), for any n, simply stall.  Note that
-     * if on-exit finalizers are enabled they're run iff the shutdown is
-     * initiated by an exit(0); they're never run on exit(n) for n != 0 or in
-     * response to SIGINT, SIGTERM, etc.
-     */
-    private static void sequence() {
-        synchronized (lock) {
-            /* Guard against the possibility of a daemon thread invoking exit
-             * after DestroyJavaVM initiates the shutdown sequence
-             */
-            if (state != HOOKS) return;
-        }
-        runHooks();
-        boolean rfoe;
-        synchronized (lock) {
-            state = FINALIZERS;
-            rfoe = runFinalizersOnExit;
-        }
-        if (rfoe) runAllFinalizers();
-    }
-
-
     /* Invoked by Runtime.exit, which does all the security checks.
      * Also invoked by handlers for system-provided termination events,
      * which should pass a nonzero status code.
      */
     static void exit(int status) {
-        boolean runMoreFinalizers = false;
         synchronized (lock) {
-            if (status != 0) runFinalizersOnExit = false;
-            switch (state) {
-            case RUNNING:       /* Initiate shutdown */
-                state = HOOKS;
-                break;
-            case HOOKS:         /* Stall and halt */
-                break;
-            case FINALIZERS:
-                if (status != 0) {
-                    /* Halt immediately on nonzero status */
-                    halt(status);
-                } else {
-                    /* Compatibility with old behavior:
-                     * Run more finalizers and then halt
-                     */
-                    runMoreFinalizers = runFinalizersOnExit;
-                }
-                break;
+            if (status != 0 && VM.isShutdown()) {
+                /* Halt immediately on nonzero status */
+                halt(status);
             }
         }
-        if (runMoreFinalizers) {
-            runAllFinalizers();
-            halt(status);
-        }
         synchronized (Shutdown.class) {
             /* Synchronize on the class object, causing any other thread
              * that attempts to initiate shutdown to stall indefinitely
              */
-            sequence();
+            runHooks();
             halt(status);
         }
     }
@@ -220,18 +178,8 @@
      * actually halt the VM.
      */
     static void shutdown() {
-        synchronized (lock) {
-            switch (state) {
-            case RUNNING:       /* Initiate shutdown */
-                state = HOOKS;
-                break;
-            case HOOKS:         /* Stall and then return */
-            case FINALIZERS:
-                break;
-            }
-        }
         synchronized (Shutdown.class) {
-            sequence();
+            runHooks();
         }
     }
 
--- a/src/java.base/share/classes/java/lang/System.java	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/java.base/share/classes/java/lang/System.java	Fri Feb 23 12:10:56 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2018, 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
@@ -1766,38 +1766,6 @@
     }
 
     /**
-     * Enable or disable finalization on exit; doing so specifies that the
-     * finalizers of all objects that have finalizers that have not yet been
-     * automatically invoked are to be run before the Java runtime exits.
-     * By default, finalization on exit is disabled.
-     *
-     * <p>If there is a security manager,
-     * its <code>checkExit</code> method is first called
-     * with 0 as its argument to ensure the exit is allowed.
-     * This could result in a SecurityException.
-     *
-     * @deprecated  This method is inherently unsafe.  It may result in
-     *      finalizers being called on live objects while other threads are
-     *      concurrently manipulating those objects, resulting in erratic
-     *      behavior or deadlock.
-     *      This method is subject to removal in a future version of Java SE.
-     * @param value indicating enabling or disabling of finalization
-     * @throws  SecurityException
-     *        if a security manager exists and its <code>checkExit</code>
-     *        method doesn't allow the exit.
-     *
-     * @see     java.lang.Runtime#exit(int)
-     * @see     java.lang.Runtime#gc()
-     * @see     java.lang.SecurityManager#checkExit(int)
-     * @since   1.1
-     */
-    @Deprecated(since="1.2", forRemoval=true)
-    @SuppressWarnings("removal")
-    public static void runFinalizersOnExit(boolean value) {
-        Runtime.runFinalizersOnExit(value);
-    }
-
-    /**
      * Loads the native library specified by the filename argument.  The filename
      * argument must be an absolute path name.
      *
--- a/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html	Fri Feb 23 12:10:56 2018 -0800
@@ -1,6 +1,6 @@
 <!doctype html>
 <!--
- Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2005, 2018, 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
@@ -346,19 +346,6 @@
 the manner of <code>Thread.suspend</code>. (In fact, it is roughly
 equivalent to <code>Thread.suspend</code> without the possibility
 of a subsequent <code>Thread.resume</code>.)
-<hr>
-<h3>Why is <code>Runtime.runFinalizersOnExit</code>
-deprecated?</h3>
-Because it is inherently unsafe. It may result in finalizers being
-called on live objects while other threads are concurrently
-manipulating those objects, resulting in erratic behavior or
-deadlock. While this problem could be prevented if the class whose
-objects are being finalized were coded to "defend against" this
-call, most programmers do <i>not</i> defend against it. They assume
-that an object is dead at the time that its finalizer is called.
-<p>Further, the call is not "thread-safe" in the sense that it sets
-a VM-global flag. This forces <i>every</i> class with a finalizer
-to defend against the finalization of live objects!</p>
 <p><!-- Body text ends here --></p>
 </body>
 </html>
--- a/src/java.base/share/classes/java/lang/ref/Finalizer.java	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/java.base/share/classes/java/lang/ref/Finalizer.java	Fri Feb 23 12:10:56 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, 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
@@ -66,7 +66,7 @@
         new Finalizer(finalizee);
     }
 
-    private void deregisterAndRunFinalizer(JavaLangAccess jla) {
+    private void runFinalizer(JavaLangAccess jla) {
         synchronized (lock) {
             if (this.next == this)      // already finalized
                 return;
@@ -80,17 +80,14 @@
             this.prev = null;
             this.next = this;           // mark as finalized
         }
-        runFinalizer(jla);
-    }
 
-    private void runFinalizer(JavaLangAccess jla) {
         try {
             Object finalizee = this.get();
             if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
                 jla.invokeFinalize(finalizee);
 
-                /* Clear stack slot containing this variable, to decrease
-                   the chances of false retention with a conservative GC */
+                // Clear stack slot containing this variable, to decrease
+                // the chances of false retention with a conservative GC
                 finalizee = null;
             }
         } catch (Throwable x) { }
@@ -98,17 +95,14 @@
     }
 
     /* Create a privileged secondary finalizer thread in the system thread
-       group for the given Runnable, and wait for it to complete.
-
-       This method is used by both runFinalization and runFinalizersOnExit.
-       The former method invokes all pending finalizers, while the latter
-       invokes all uninvoked finalizers if on-exit finalization has been
-       enabled.
-
-       These two methods could have been implemented by offloading their work
-       to the regular finalizer thread and waiting for that thread to finish.
-       The advantage of creating a fresh thread, however, is that it insulates
-       invokers of these methods from a stalled or deadlocked finalizer thread.
+     * group for the given Runnable, and wait for it to complete.
+     *
+     * This method is used by runFinalization.
+     *
+     * It could have been implemented by offloading the work to the
+     * regular finalizer thread and waiting for that thread to finish.
+     * The advantage of creating a fresh thread, however, is that it insulates
+     * invokers of that method from a stalled or deadlocked finalizer thread.
      */
     private static void forkSecondaryFinalizer(final Runnable proc) {
         AccessController.doPrivileged(
@@ -144,40 +138,11 @@
                 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
                 running = true;
                 for (Finalizer f; (f = (Finalizer)queue.poll()) != null; )
-                    f.deregisterAndRunFinalizer(jla);
+                    f.runFinalizer(jla);
             }
         });
     }
 
-    /* Invoked by java.lang.Shutdown */
-    static void runAllFinalizers() {
-        if (VM.initLevel() == 0) {
-            return;
-        }
-
-        forkSecondaryFinalizer(new Runnable() {
-            private volatile boolean running;
-            public void run() {
-                // in case of recursive call to run()
-                if (running)
-                    return;
-                final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
-                running = true;
-                for (;;) {
-                    // "pollFirst" from unfinalized
-                    Finalizer f;
-                    synchronized (lock) {
-                        f = unfinalized;
-                        if (f == null) break;
-                        unfinalized = f.next;
-                        if (unfinalized != null)
-                            unfinalized.prev = null;
-                        f.next = f; // mark as finalized
-                    }
-                    f.runFinalizer(jla);
-                }}});
-    }
-
     private static class FinalizerThread extends Thread {
         private volatile boolean running;
         FinalizerThread(ThreadGroup g) {
@@ -203,7 +168,7 @@
             for (;;) {
                 try {
                     Finalizer f = (Finalizer)queue.remove();
-                    f.deregisterAndRunFinalizer(jla);
+                    f.runFinalizer(jla);
                 } catch (InterruptedException x) {
                     // ignore and continue
                 }
--- a/src/java.base/share/classes/jdk/internal/misc/VM.java	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/java.base/share/classes/jdk/internal/misc/VM.java	Fri Feb 23 12:10:56 2018 -0800
@@ -27,9 +27,7 @@
 
 import static java.lang.Thread.State.*;
 import java.util.Map;
-import java.util.HashMap;
 import java.util.Properties;
-import java.util.Collections;
 
 public class VM {
 
@@ -38,6 +36,8 @@
     private static final int MODULE_SYSTEM_INITED        = 2;
     private static final int SYSTEM_LOADER_INITIALIZING  = 3;
     private static final int SYSTEM_BOOTED               = 4;
+    private static final int SYSTEM_SHUTDOWN             = 5;
+
 
     // 0, 1, 2, ...
     private static volatile int initLevel;
@@ -52,7 +52,7 @@
      */
     public static void initLevel(int value) {
         synchronized (lock) {
-            if (value <= initLevel || value > SYSTEM_BOOTED)
+            if (value <= initLevel || value > SYSTEM_SHUTDOWN)
                 throw new InternalError("Bad level: " + value);
             initLevel = value;
             lock.notifyAll();
@@ -94,6 +94,23 @@
         return initLevel >= SYSTEM_BOOTED;
     }
 
+    /**
+     * Set shutdown state.  Shutdown completes when all registered shutdown
+     * hooks have been run.
+     *
+     * @see java.lang.Shutdown
+     */
+    public static void shutdown() {
+        initLevel(SYSTEM_SHUTDOWN);
+    }
+
+    /**
+     * Returns {@code true} if the VM has been shutdown
+     */
+    public static boolean isShutdown() {
+        return initLevel == SYSTEM_SHUTDOWN;
+    }
+
     // A user-settable upper limit on the maximum amount of allocatable direct
     // buffer memory.  This value may be changed during VM initialization if
     // "java" is launched with "-XX:MaxDirectMemorySize=<size>".
--- a/src/java.base/share/native/libjava/Shutdown.c	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/java.base/share/native/libjava/Shutdown.c	Fri Feb 23 12:10:56 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, 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
@@ -35,17 +35,3 @@
 {
     JVM_Halt(code);
 }
-
-
-JNIEXPORT void JNICALL
-Java_java_lang_Shutdown_runAllFinalizers(JNIEnv *env, jclass ignored)
-{
-    jclass cl;
-    jmethodID mid;
-
-    if ((cl = (*env)->FindClass(env, "java/lang/ref/Finalizer"))
-        && (mid = (*env)->GetStaticMethodID(env, cl,
-                                            "runAllFinalizers", "()V"))) {
-        (*env)->CallStaticVoidMethod(env, cl, mid);
-    }
-}
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Main.java	Fri Feb 23 12:10:56 2018 -0800
@@ -80,8 +80,8 @@
  *  - handling of covariant overrides
  *  - handling of override of method found in multiple superinterfaces
  *  - convert type/method/field output to Java source like syntax, e.g.
- *      instead of java/lang/Runtime.runFinalizersOnExit(Z)V
- *      print void java.lang.Runtime.runFinalizersOnExit(boolean)
+ *      instead of java/lang/Character.isJavaLetter(C)Z
+ *      print void java.lang.Character.isJavaLetter(char)boolean
  *  - more example output in man page
  *  - more rigorous GNU style option parsing; use joptsimple?
  *
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/internals.md	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/internals.md	Fri Feb 23 12:10:56 2018 -0800
@@ -195,15 +195,14 @@
 **EXAMPLE OUTPUT**
 
 Given the following method declaration and annotation from the
-`java.lang.Runtime` class,
+`java.lang.Character` class,
 
-            @Deprecated(since="1.2",
-                        forRemoval=true)
-            public static void runFinalizersOnExit(boolean value)
+            @Deprecated(since="1.1")
+            public static boolean isJavaLetter(char ch)
 
 the following line will be emitted from **jdeprscan -Xprint-csv**:
 
-            METHOD,java/lang/Runtime,runFinalizersOnExit(Z)V,1.2,true
+            METHOD,java/lang/Character,isJavaLetter(C)Z,1.1,false
 
 
 [RFC]: https://www.ietf.org/rfc/rfc4180.txt
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md	Fri Feb 23 14:26:29 2018 -0500
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/readme.md	Fri Feb 23 12:10:56 2018 -0800
@@ -1,6 +1,6 @@
 <!--
 
-Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2016, 2018, 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
@@ -134,30 +134,30 @@
 The output is a report that lists program elements that use deprecated
 APIs. Output is subject to change.
 
-Consider the following declarations from Java SE 9:
+Consider the following declarations:
 
         // java.lang.Boolean
 
         @Deprecated(since="9")
         public Boolean(boolean value)
 
-        // java.lang.Runtime
+        // java.lang.Thread
 
-        @Deprecated(since="1.2", forRemoval=true)
-        public static void runFinalizersOnExit(boolean value)
+        @Deprecated(since="1.5", forRemoval=true)
+        public void destroy()
 
 Running **jdeprscan** over a class that calls these methods will result
 in output something like the following:
 
         class Example uses method java/lang/Boolean.<init>(Z)V deprecated
-        class Example uses method java/lang/Runtime.runFinalizersOnExit(Z)V deprecated for removal
+        class Example uses method java/lang/Thread.destroy()V deprecated for removal
 
 Running **jdeprscan** with the `--list` option will result in output
 including something like the following:
 
         ...
         @Deprecated(since="9") java.lang.Boolean(boolean)
-        @Deprecated(since="1.2", forRemoval=true) void java.lang.Runtime.runFinalizersOnExit(boolean)
+        @Deprecated(since="1.5", forRemoval=true) void java.lang.Thread.destroy()
         ...
 
 **NOTES**
--- a/test/hotspot/jtreg/testlibrary/jittester/conf/exclude.methods.lst	Fri Feb 23 14:26:29 2018 -0500
+++ b/test/hotspot/jtreg/testlibrary/jittester/conf/exclude.methods.lst	Fri Feb 23 12:10:56 2018 -0800
@@ -12,7 +12,6 @@
 java/lang/String::format(Ljava/util/Locale;Ljava/lang/String;[Ljava/lang/Object;)
 java/lang/System::exit(I)
 java/lang/System::inheritedChannel()
-java/lang/System::runFinalizersOnExit(Z)
 java/util/AbstractSet::toString()
 java/util/HashSet::toString()
 java/lang/RuntimeException::setStackTrace([Ljava/lang/StackTraceElement;)
--- a/test/jdk/java/lang/Runtime/shutdown/Basic.java	Fri Feb 23 14:26:29 2018 -0500
+++ b/test/jdk/java/lang/Runtime/shutdown/Basic.java	Fri Feb 23 12:10:56 2018 -0800
@@ -49,12 +49,13 @@
     static Runtime rt = Runtime.getRuntime();
     static PrintStream out = System.out;
 
+    // Expect that no finalizer is invoked at exit
     @DataProvider(name = "testcase")
     public Object[][] getTestCase() {
         return new Object[][] {
-            { "fallThrough", 0, "h1", "f1" },
-            { "exit0",       0, "h1", "f1" },
-            { "exit0NoHook", 0, "",   "f1" },
+            { "fallThrough", 0, "h1", "" },
+            { "exit0",       0, "h1", "" },
+            { "exit0NoHook", 0, "",   "" },
             { "exit1",       1, "h1", "" },
             { "exit1NoHook", 1, "",   "" },
             { "halt",        0, "",   "" },
@@ -112,19 +113,16 @@
     public static void fallThrough() throws Exception {
         rt.addShutdownHook(new Hook("h1"));
         Fin f = new Fin("f1");
-        rt.runFinalizersOnExit(true);
     }
 
     public static void exit0() throws Exception {
         rt.addShutdownHook(new Hook("h1"));
         Fin f = new Fin("f1");
-        rt.runFinalizersOnExit(true);
         rt.exit(0);
     }
 
     public static void exit0NoHook() throws Exception {
         Fin f = new Fin("f1");
-        rt.runFinalizersOnExit(true);
         rt.exit(0);
     }
 
@@ -132,13 +130,11 @@
     public static void exit1() throws Exception {
         rt.addShutdownHook(new Hook("h1"));
         Fin f = new Fin("f1");
-        rt.runFinalizersOnExit(true);
         rt.exit(1);
     }
 
     public static void exit1NoHook() throws Exception {
         Fin f = new Fin("f1");
-        rt.runFinalizersOnExit(true);
         rt.exit(1);
     }
 
@@ -146,13 +142,11 @@
         rt.addShutdownHook(new Hook("h1") {
             public void go() { rt.halt(1); }});
         Fin f = new Fin("f1") { public void go() { rt.halt(1); }};
-        rt.runFinalizersOnExit(true);
         rt.halt(0);
     }
 
     public static void haltNoHook() throws Exception {
         Fin f = new Fin("f1") { public void go() { rt.halt(1); }};
-        rt.runFinalizersOnExit(true);
         rt.halt(0);
     }
 
@@ -160,7 +154,6 @@
         rt.addShutdownHook(new Hook("h1") {
             public void go() { rt.halt(0); }});
         Fin f = new Fin("f1");
-        rt.runFinalizersOnExit(true);
         rt.exit(1);
     }
 
@@ -191,52 +184,9 @@
         rt.exit(1);
     }
 
-
-    /* The following two methods are provided for manual testing only.
-     * Neither test is suitable for being run from within the harness.
-     */
-
-    public static void awt() throws Exception {
-        final Frame f = new Frame();
-        final TextArea ta = new TextArea();
-        Fin fx = new Fin("f1");
-        rt.runFinalizersOnExit(true);
-        rt.addShutdownHook(new Hook("h1") {
-            public void go() {
-                ta.setText("Hooked!");
-                out.println("Hooked!");
-                try {
-                    Thread.sleep(1000);
-                } catch (InterruptedException x) { }
-                ta.append("\nSleep 1");
-                out.println("Sleep 1");
-                try {
-                    Thread.sleep(1000);
-                } catch (InterruptedException x) { }
-                ta.append("\nSleep 2");
-                out.println("Sleep 2");
-            }});
-        f.addWindowListener(new WindowAdapter() {
-            public void windowClosing(WindowEvent e) {
-                out.println("Closing...");
-                ta.setText("Closing...");
-                try {
-                    Thread.sleep(1000);
-                } catch (InterruptedException x) { }
-                f.dispose();
-                rt.exit(42);
-            }});
-        ta.setText("Terminate me!");
-        f.add(ta);
-        f.pack();
-        f.show();
-        Thread.sleep(10000);
-    }
-
     /* For INT, HUP, TERM */
     public static void stall() throws Exception {
         Fin f = new Fin("f1");
-        rt.runFinalizersOnExit(true);
         rt.addShutdownHook(new Hook("h1"));
         out.print("Type ^C now: ");
         out.flush();
--- a/test/jdk/java/lang/System/ExitFinalizersAndJIT.java	Fri Feb 23 14:26:29 2018 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 1998, 2010, 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 4119554
-   @summary runFinalizersOnExit(true) causes JIT to be unloaded and
-            crashes the VM.  Interim fix for 1.2 beta4 -- don't unload
-            native libraries loaded by system classes.
-   @run main/othervm ExitFinalizersAndJIT
-*/
-
-public class ExitFinalizersAndJIT {
-    public static void main(String[] args) throws Exception {
-        System.runFinalizersOnExit(true);
-    }
-}
--- a/test/jdk/java/lang/System/finalization/FinExit.java	Fri Feb 23 14:26:29 2018 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 1998, 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 4116016
-   @summary Ensure that finalizers are not invoked more than once when on-exit
-            finalization is enabled and a finalizer invokes System.exit after
-            System.exit has already been invoked
-   @build FinExit
-   @run shell FinExit.sh
- */
-
-
-public class FinExit {
-
-    boolean finalized = false;
-
-    public void finalize() {
-        if (finalized) {
-            System.out.println("2");
-        } else {
-            finalized = true;
-            System.out.println("1");
-            System.exit(0);
-        }
-    }
-
-    public static void main(String[] args) throws Exception {
-        System.runFinalizersOnExit(true);
-        Object o = new FinExit();
-        System.exit(0);
-    }
-
-}
--- a/test/jdk/java/lang/System/finalization/FinExit.sh	Fri Feb 23 14:26:29 2018 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-#! /bin/sh
-
-#
-# Copyright (c) 1998, 2010, 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.
-#
-
-#
-
-# We only want the first character, Windows might add CRLF
-x=`$TESTJAVA/bin/java ${TESTVMOPTS} -cp "$TESTCLASSES" FinExit | cut -c1`
-echo $x
-if [ "x$x" != "x1" ]; then
-  echo On-exit finalizer invoked twice
-  exit 1
-else
-  exit 0
-fi