diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java
index a4d09cd8699..6621805c6a5 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Source.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Source.java
@@ -240,6 +240,9 @@ public enum Source {
     public boolean allowPostApplicabilityVarargsAccessCheck() {
         return compareTo(JDK1_8) >= 0;
     }
+    public boolean allowPrivateSafeVarargs() {
+        return compareTo(JDK1_9) >= 0;
+    }
     public static SourceVersion toSourceVersion(Source source) {
         switch(source) {
         case JDK1_2:
diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
index 139be89d75e..43728013aa9 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java
@@ -127,6 +127,7 @@ public class Check {
         allowSimplifiedVarargs = source.allowSimplifiedVarargs();
         allowDefaultMethods = source.allowDefaultMethods();
         allowStrictMethodClashCheck = source.allowStrictMethodClashCheck();
+        allowPrivateSafeVarargs = source.allowPrivateSafeVarargs();
         complexInference = options.isSet("complexinference");
         warnOnSyntheticConflicts = options.isSet("warnOnSyntheticConflicts");
         suppressAbortOnBadClassFile = options.isSet("suppressAbortOnBadClassFile");
@@ -181,6 +182,10 @@ public class Check {
      */
     boolean allowStrictMethodClashCheck;
 
+    /** Switch: can the @SafeVarargs annotation be applied to private methods?
+     */
+    boolean allowPrivateSafeVarargs;
+
     /** Switch: -complexinference option set?
      */
     boolean complexInference;
@@ -816,8 +821,10 @@ public class Check {
             if (varargElemType != null) {
                 log.error(tree,
                         "varargs.invalid.trustme.anno",
-                        syms.trustMeType.tsym,
-                        diags.fragment("varargs.trustme.on.virtual.varargs", m));
+                          syms.trustMeType.tsym,
+                          allowPrivateSafeVarargs ?
+                          diags.fragment("varargs.trustme.on.virtual.varargs", m) :
+                          diags.fragment("varargs.trustme.on.virtual.varargs.final.only", m));
             } else {
                 log.error(tree,
                             "varargs.invalid.trustme.anno",
@@ -840,7 +847,8 @@ public class Check {
         private boolean isTrustMeAllowedOnMethod(Symbol s) {
             return (s.flags() & VARARGS) != 0 &&
                 (s.isConstructor() ||
-                    (s.flags() & (STATIC | FINAL)) != 0);
+                    (s.flags() & (STATIC | FINAL |
+                                  (allowPrivateSafeVarargs ? PRIVATE : 0) )) != 0);
         }
 
     Type checkMethod(final Type mtype,
diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
index 658a97dce22..5df19716849 100644
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties
@@ -1101,6 +1101,10 @@ compiler.misc.varargs.trustme.on.non.varargs.meth=\
 
 # 0: symbol
 compiler.misc.varargs.trustme.on.virtual.varargs=\
+    Instance method {0} is neither final nor private.
+
+# 0: symbol
+compiler.misc.varargs.trustme.on.virtual.varargs.final.only=\
     Instance method {0} is not final.
 
 # 0: type, 1: symbol kind, 2: symbol
diff --git a/langtools/test/tools/javac/diags/examples/VarargsFinalOnly.java b/langtools/test/tools/javac/diags/examples/VarargsFinalOnly.java
new file mode 100644
index 00000000000..167bf3efcc4
--- /dev/null
+++ b/langtools/test/tools/javac/diags/examples/VarargsFinalOnly.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2010, 2014, 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.
+ */
+
+// key: compiler.err.varargs.invalid.trustme.anno
+// key: compiler.misc.varargs.trustme.on.virtual.varargs.final.only
+// options: -source 1.8 -Xlint:varargs,-options,-unchecked
+
+import java.util.List;
+
+class VarargsFinalOnly {
+    @SafeVarargs void m(List<String>... args) { }
+}
diff --git a/langtools/test/tools/javac/varargs/warning/Warn4.java b/langtools/test/tools/javac/varargs/warning/Warn4.java
index 1a068c74244..4598c483fd4 100644
--- a/langtools/test/tools/javac/varargs/warning/Warn4.java
+++ b/langtools/test/tools/javac/varargs/warning/Warn4.java
@@ -73,13 +73,15 @@ public class Warn4
                 ModifierKind modKind) {
             switch(this) {
                 case VARARGS:
-                    return source == SourceLevel.JDK_6 ||
+                    return source.compareTo(SourceLevel.JDK_7) < 0 ||
                             suppressLevelDecl == SuppressLevel.UNCHECKED ||
                             trustMe == TrustMe.TRUST;
                 case UNCHECKED:
                     return suppressLevelClient == SuppressLevel.UNCHECKED ||
-                        (trustMe == TrustMe.TRUST && modKind !=
-                            ModifierKind.NONE && source == SourceLevel.JDK_7);
+                        (trustMe == TrustMe.TRUST &&
+                         (((modKind == ModifierKind.FINAL || modKind == ModifierKind.STATIC) &&
+                           source.compareTo( SourceLevel.JDK_7) >= 0 ) ||
+                          (modKind == ModifierKind.PRIVATE && source.compareTo( SourceLevel.JDK_9) >= 0 )));
             }
 
             SuppressLevel supLev = this == VARARGS ?
@@ -92,7 +94,8 @@ public class Warn4
 
     enum SourceLevel {
         JDK_6("6"),
-        JDK_7("7");
+        JDK_7("7"),
+        JDK_9("9");
 
         String sourceKey;
 
@@ -115,7 +118,8 @@ public class Warn4
     enum ModifierKind {
         NONE(" "),
         FINAL("final "),
-        STATIC("static ");
+        STATIC("static "),
+        PRIVATE("private ");
 
         String mod;
 
diff --git a/langtools/test/tools/javac/varargs/warning/Warn5.java b/langtools/test/tools/javac/varargs/warning/Warn5.java
index e45cd361637..b73d1af5fa8 100644
--- a/langtools/test/tools/javac/varargs/warning/Warn5.java
+++ b/langtools/test/tools/javac/varargs/warning/Warn5.java
@@ -89,7 +89,8 @@ public class Warn5
     enum ModifierKind {
         NONE(""),
         FINAL("final"),
-        STATIC("static");
+        STATIC("static"),
+        PRIVATE("private");
 
         String mod;
 
@@ -111,7 +112,8 @@ public class Warn5
 
     enum SourceLevel {
         JDK_6("6"),
-        JDK_7("7");
+        JDK_7("7"),
+        JDK_9("9");
 
         String sourceKey;
 
@@ -238,7 +240,7 @@ public class Warn5
         EnumSet<WarningKind> expectedWarnings =
                 EnumSet.noneOf(WarningKind.class);
 
-        if (sourceLevel == SourceLevel.JDK_7 &&
+        if (sourceLevel.compareTo(SourceLevel.JDK_7) >= 0 &&
                 trustMe == TrustMe.TRUST &&
                 suppressLevel != SuppressLevel.VARARGS &&
                 xlint != XlintOption.NONE &&
@@ -247,11 +249,12 @@ public class Warn5
                 body.hasAliasing &&
                 (methKind == MethodKind.CONSTRUCTOR ||
                 (methKind == MethodKind.METHOD &&
-                modKind != ModifierKind.NONE))) {
+                 modKind == ModifierKind.FINAL || modKind == ModifierKind.STATIC ||
+                 (modKind == ModifierKind.PRIVATE && sourceLevel.compareTo(SourceLevel.JDK_9) >= 0)))) {
             expectedWarnings.add(WarningKind.UNSAFE_BODY);
         }
 
-        if (sourceLevel == SourceLevel.JDK_7 &&
+        if (sourceLevel.compareTo(SourceLevel.JDK_7) >= 0 &&
                 trustMe == TrustMe.DONT_TRUST &&
                 sig.isVarargs &&
                 !sig.isReifiableArg &&
@@ -259,20 +262,22 @@ public class Warn5
             expectedWarnings.add(WarningKind.UNSAFE_DECL);
         }
 
-        if (sourceLevel == SourceLevel.JDK_7 &&
+        if (sourceLevel.compareTo(SourceLevel.JDK_7) >= 0 &&
                 trustMe == TrustMe.TRUST &&
                 (!sig.isVarargs ||
-                (modKind == ModifierKind.NONE &&
-                methKind == MethodKind.METHOD))) {
+                 ((modKind == ModifierKind.NONE ||
+                 modKind == ModifierKind.PRIVATE && sourceLevel.compareTo(SourceLevel.JDK_9) < 0 ) &&
+                 methKind == MethodKind.METHOD))) {
             expectedWarnings.add(WarningKind.MALFORMED_SAFEVARARGS);
         }
 
-        if (sourceLevel == SourceLevel.JDK_7 &&
+        if (sourceLevel.compareTo(SourceLevel.JDK_7) >= 0 &&
                 trustMe == TrustMe.TRUST &&
                 xlint != XlintOption.NONE &&
                 suppressLevel != SuppressLevel.VARARGS &&
-                (modKind != ModifierKind.NONE ||
-                methKind == MethodKind.CONSTRUCTOR) &&
+                (modKind == ModifierKind.FINAL || modKind == ModifierKind.STATIC ||
+                 (modKind == ModifierKind.PRIVATE && sourceLevel.compareTo(SourceLevel.JDK_9) >= 0) ||
+                 methKind == MethodKind.CONSTRUCTOR) &&
                 sig.isVarargs &&
                 sig.isReifiableArg) {
             expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS);
@@ -283,6 +288,7 @@ public class Warn5
             throw new Error("invalid diagnostics for source:\n" +
                     source.getCharContent(true) +
                     "\nOptions: " + xlint.getXlintOption() +
+                    "\nSource Level: " + sourceLevel +
                     "\nExpected warnings: " + expectedWarnings +
                     "\nFound warnings: " + dc.warnings);
         }