changeset 52948:cb71f66e8e19 intrinsics-project

imported patch intrinsics
author jlaskey
date Wed, 31 Oct 2018 11:08:50 -0300
parents cb6d96ac7cdb
children 465f6d70456a
files src/java.base/share/classes/java/io/PrintStream.java src/java.base/share/classes/java/io/PrintWriter.java src/java.base/share/classes/java/lang/String.java src/java.base/share/classes/java/lang/compiler/IntrinsicCandidate.java src/java.base/share/classes/java/lang/invoke/FormatterBootstraps.java src/java.base/share/classes/java/lang/invoke/IntrinsicFactory.java src/java.base/share/classes/java/lang/invoke/ObjectsBootstraps.java src/java.base/share/classes/java/util/Formatter.java src/java.base/share/classes/java/util/Objects.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/IntrinsicsVisitor.java src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/FormatterProcessorFactory.java src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/HashProcessorFactory.java src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/IntrinsicContext.java src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/IntrinsicProcessor.java src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/IntrinsicProcessorFactory.java src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/Intrinsics.java src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/StringProcessorFactory.java src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties src/jdk.compiler/share/classes/module-info.java test/jdk/java/util/Formatter/Basic-X.java.template test/jdk/java/util/Formatter/BasicBigDecimal.java test/jdk/java/util/Formatter/BasicBigInteger.java test/jdk/java/util/Formatter/BasicBoolean.java test/jdk/java/util/Formatter/BasicBooleanObject.java test/jdk/java/util/Formatter/BasicByte.java test/jdk/java/util/Formatter/BasicByteObject.java test/jdk/java/util/Formatter/BasicChar.java test/jdk/java/util/Formatter/BasicCharObject.java test/jdk/java/util/Formatter/BasicDateTime.java test/jdk/java/util/Formatter/BasicDouble.java test/jdk/java/util/Formatter/BasicDoubleObject.java test/jdk/java/util/Formatter/BasicFloat.java test/jdk/java/util/Formatter/BasicFloatObject.java test/jdk/java/util/Formatter/BasicInt.java test/jdk/java/util/Formatter/BasicIntObject.java test/jdk/java/util/Formatter/BasicLong.java test/jdk/java/util/Formatter/BasicLongObject.java test/jdk/java/util/Formatter/BasicShort.java test/jdk/java/util/Formatter/BasicShortObject.java test/jdk/java/util/Formatter/EncodingTest.java test/jdk/java/util/Formatter/FormatLocale.java test/jdk/java/util/Formatter/JavacIntrinsicsSupport.java test/jdk/java/util/Formatter/NullArg.java
diffstat 45 files changed, 4793 insertions(+), 215 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/io/PrintStream.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/src/java.base/share/classes/java/io/PrintStream.java	Wed Oct 31 11:08:50 2018 -0300
@@ -25,11 +25,12 @@
 
 package java.io;
 
-import java.util.Formatter;
-import java.util.Locale;
+import java.lang.compiler.IntrinsicCandidate;
 import java.nio.charset.Charset;
 import java.nio.charset.IllegalCharsetNameException;
 import java.nio.charset.UnsupportedCharsetException;
+import java.util.Formatter;
+import java.util.Locale;
 
 /**
  * A {@code PrintStream} adds functionality to another output stream,
@@ -945,6 +946,7 @@
      *
      * @since  1.5
      */
+    @IntrinsicCandidate
     public PrintStream printf(String format, Object ... args) {
         return format(format, args);
     }
@@ -997,6 +999,7 @@
      *
      * @since  1.5
      */
+    @IntrinsicCandidate
     public PrintStream printf(Locale l, String format, Object ... args) {
         return format(l, format, args);
     }
@@ -1042,6 +1045,7 @@
      *
      * @since  1.5
      */
+    @IntrinsicCandidate
     public PrintStream format(String format, Object ... args) {
         try {
             synchronized (this) {
@@ -1101,6 +1105,7 @@
      *
      * @since  1.5
      */
+    @IntrinsicCandidate
     public PrintStream format(Locale l, String format, Object ... args) {
         try {
             synchronized (this) {
--- a/src/java.base/share/classes/java/io/PrintWriter.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/src/java.base/share/classes/java/io/PrintWriter.java	Wed Oct 31 11:08:50 2018 -0300
@@ -25,12 +25,13 @@
 
 package java.io;
 
+import java.lang.compiler.IntrinsicCandidate;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
 import java.util.Objects;
 import java.util.Formatter;
 import java.util.Locale;
-import java.nio.charset.Charset;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
 
 /**
  * Prints formatted representations of objects to a text-output stream.  This
@@ -885,6 +886,7 @@
      *
      * @since  1.5
      */
+    @IntrinsicCandidate
     public PrintWriter printf(String format, Object ... args) {
         return format(format, args);
     }
@@ -922,6 +924,7 @@
      *         {@code null} argument depends on the <a
      *         href="../util/Formatter.html#syntax">conversion</a>.
      *
+     *
      * @throws  java.util.IllegalFormatException
      *          If a format string contains an illegal syntax, a format
      *          specifier that is incompatible with the given arguments,
@@ -938,6 +941,7 @@
      *
      * @since  1.5
      */
+    @IntrinsicCandidate
     public PrintWriter printf(Locale l, String format, Object ... args) {
         return format(l, format, args);
     }
@@ -982,6 +986,7 @@
      *
      * @since  1.5
      */
+    @IntrinsicCandidate
     public PrintWriter format(String format, Object ... args) {
         try {
             synchronized (lock) {
@@ -1042,6 +1047,7 @@
      *
      * @since  1.5
      */
+    @IntrinsicCandidate
     public PrintWriter format(Locale l, String format, Object ... args) {
         try {
             synchronized (lock) {
--- a/src/java.base/share/classes/java/lang/String.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/src/java.base/share/classes/java/lang/String.java	Wed Oct 31 11:08:50 2018 -0300
@@ -29,6 +29,7 @@
 import java.io.UnsupportedEncodingException;
 import java.lang.annotation.Native;
 import java.lang.invoke.MethodHandles;
+import java.lang.compiler.IntrinsicCandidate;
 import java.lang.constant.Constable;
 import java.lang.constant.ConstantDesc;
 import java.nio.charset.Charset;
@@ -661,6 +662,7 @@
      * @return  the length of the sequence of characters represented by this
      *          object.
      */
+    @IntrinsicCandidate
     public int length() {
         return value.length >> coder();
     }
@@ -2027,6 +2029,7 @@
      * @since 1.4
      * @spec JSR-51
      */
+    @IntrinsicCandidate
     public boolean matches(String regex) {
         return Pattern.matches(regex, this);
     }
@@ -2084,6 +2087,7 @@
      * @since 1.4
      * @spec JSR-51
      */
+    @IntrinsicCandidate
     public String replaceFirst(String regex, String replacement) {
         return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
     }
@@ -2129,6 +2133,7 @@
      * @since 1.4
      * @spec JSR-51
      */
+    @IntrinsicCandidate
     public String replaceAll(String regex, String replacement) {
         return Pattern.compile(regex).matcher(this).replaceAll(replacement);
     }
@@ -2269,6 +2274,7 @@
      * @since 1.4
      * @spec JSR-51
      */
+    @IntrinsicCandidate
     public String[] split(String regex, int limit) {
         /* fastpath if the regex is a
          (1)one-char String and this character is not one of the
@@ -2367,6 +2373,7 @@
      * @since 1.4
      * @spec JSR-51
      */
+    @IntrinsicCandidate
     public String[] split(String regex) {
         return split(regex, 0);
     }
@@ -2679,6 +2686,7 @@
      *
      * @since 11
      */
+    @IntrinsicCandidate
     public String strip() {
         String ret = isLatin1() ? StringLatin1.strip(value)
                                 : StringUTF16.strip(value);
@@ -2709,6 +2717,7 @@
      *
      * @since 11
      */
+    @IntrinsicCandidate
     public String stripLeading() {
         String ret = isLatin1() ? StringLatin1.stripLeading(value)
                                 : StringUTF16.stripLeading(value);
@@ -2739,6 +2748,7 @@
      *
      * @since 11
      */
+    @IntrinsicCandidate
     public String stripTrailing() {
         String ret = isLatin1() ? StringLatin1.stripTrailing(value)
                                 : StringUTF16.stripTrailing(value);
@@ -2839,6 +2849,7 @@
      *
      * @since 12
      */
+    @IntrinsicCandidate
     public String indent(int n) {
         return isEmpty() ? "" :  indent(n, false);
     }
@@ -2964,6 +2975,7 @@
      *
      * @since 12
      */
+    @IntrinsicCandidate
     public String align(int n) {
         if (isEmpty()) {
             return "";
@@ -3070,6 +3082,7 @@
      * @see  java.util.Formatter
      * @since  1.5
      */
+    @IntrinsicCandidate
     public static String format(String format, Object... args) {
         return new Formatter().format(format, args).toString();
     }
@@ -3111,11 +3124,94 @@
      * @see  java.util.Formatter
      * @since  1.5
      */
+    @IntrinsicCandidate
     public static String format(Locale l, String format, Object... args) {
         return new Formatter(l).format(format, args).toString();
     }
 
     /**
+     * Returns a formatted string using this string, as the specified
+     * <a href="../util/Formatter.html#syntax">format</a>, and
+     * arguments.
+     *
+     * <p> The locale always used is the one returned by {@link
+     * java.util.Locale#getDefault(java.util.Locale.Category)
+     * Locale.getDefault(Locale.Category)} with
+     * {@link java.util.Locale.Category#FORMAT FORMAT} category specified.
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         {@code null} argument depends on the <a
+     *         href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification.
+     *
+     * @return  A formatted string
+     *
+     * @see  java.util.Formatter
+     *
+     * @since  12
+     */
+    @IntrinsicCandidate
+    public String format(Object... args) {
+        return new Formatter().format(this, args).toString();
+    }
+
+    /**
+     * Returns a formatted string using this string, as the specified
+     * <a href="../util/Formatter.html#syntax">format</a>, the specified locale,
+     * and  arguments.
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         {@code null} argument depends on the
+     *         <a href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification
+     *
+     * @return  A formatted string
+     *
+     * @see  java.util.Formatter
+     *
+     * @since  12
+     */
+    @IntrinsicCandidate
+    public String format(Locale l, Object... args) {
+        return new Formatter(l).format(this, args).toString();
+    }
+
+    /**
      * Returns the string representation of the {@code Object} argument.
      *
      * @param   obj   an {@code Object}.
@@ -3321,6 +3417,7 @@
      *
      * @since 11
      */
+    @IntrinsicCandidate
     public String repeat(int count) {
         if (count < 0) {
             throw new IllegalArgumentException("count is negative: " + count);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/compiler/IntrinsicCandidate.java	Wed Oct 31 11:08:50 2018 -0300
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+package java.lang.compiler;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotated method is a candidate for compile time optimization.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target({ ElementType.METHOD })
+public @interface IntrinsicCandidate {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/invoke/FormatterBootstraps.java	Wed Oct 31 11:08:50 2018 -0300
@@ -0,0 +1,657 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+package java.lang.invoke;
+
+import java.io.IOException;
+import java.text.DecimalFormatSymbols;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Formatter;
+import java.util.IllegalFormatConversionException;
+import java.util.List;
+import java.util.Locale;
+import java.util.MissingFormatArgumentException;
+import java.util.UnknownFormatConversionException;
+import java.util.stream.IntStream;
+
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+import static java.lang.invoke.MethodHandles.constant;
+import static java.lang.invoke.MethodHandles.dropArguments;
+import static java.lang.invoke.MethodHandles.filterArgument;
+import static java.lang.invoke.MethodHandles.filterReturnValue;
+import static java.lang.invoke.MethodHandles.foldArguments;
+import static java.lang.invoke.MethodHandles.guardWithTest;
+import static java.lang.invoke.MethodHandles.identity;
+import static java.lang.invoke.MethodHandles.insertArguments;
+import static java.lang.invoke.MethodHandles.throwException;
+import static java.lang.invoke.MethodType.methodType;
+
+/**
+ * Bootstrapping support for Formatter intrinsics.
+ */
+public final class FormatterBootstraps {
+
+    private static final MethodHandle APPENDABLE_APPEND =
+            findVirtualMethodHandle(Appendable.class, "append", methodType(Appendable.class, CharSequence.class));
+
+    private static final MethodHandle SPECIFIER_PRINT =
+            findVirtualMethodHandle(Formatter.Specifier.class, "print",
+                    methodType(Formatter.class, Formatter.class, Object.class, Locale.class));
+    private static final MethodHandle SPECIFIER_PRINT_STRING =
+            findVirtualMethodHandle("java.util.Formatter$FormatSpecifier", "print",
+                    methodType(Formatter.class, Formatter.class, String.class, Locale.class));
+    private static final MethodHandle SPECIFIER_PRINT_INT =
+            findVirtualMethodHandle("java.util.Formatter$FormatSpecifier", "print",
+                    methodType(Formatter.class, Formatter.class, int.class, Locale.class));
+    private static final MethodHandle SPECIFIER_PRINT_LONG =
+            findVirtualMethodHandle("java.util.Formatter$FormatSpecifier", "print",
+                    methodType(Formatter.class, Formatter.class, long.class, Locale.class));
+    private static final MethodHandle SPECIFIER_PRINT_BYTE =
+            findVirtualMethodHandle("java.util.Formatter$FormatSpecifier", "print",
+                    methodType(Formatter.class, Formatter.class, byte.class, Locale.class));
+    private static final MethodHandle SPECIFIER_PRINT_SHORT =
+            findVirtualMethodHandle("java.util.Formatter$FormatSpecifier", "print",
+                    methodType(Formatter.class, Formatter.class, short.class, Locale.class));
+    private static final MethodHandle SPECIFIER_PRINT_FLOAT =
+            findVirtualMethodHandle("java.util.Formatter$FormatSpecifier", "print",
+                    methodType(Formatter.class, Formatter.class, float.class, Locale.class));
+    private static final MethodHandle SPECIFIER_PRINT_DOUBLE =
+            findVirtualMethodHandle("java.util.Formatter$FormatSpecifier", "print",
+                    methodType(Formatter.class, Formatter.class, double.class, Locale.class));
+    private static final MethodHandle SPECIFIER_PRINT_HASHCODE =
+            findVirtualMethodHandle("java.util.Formatter$FormatSpecifier", "printHashCode",
+                    methodType(Formatter.class, Formatter.class, Object.class, Locale.class));
+
+    private static final MethodHandle INT_TO_STRING =
+            findStaticMethodHandle(Integer.class, "toString", methodType(String.class, int.class));
+    private static final MethodHandle CONSTRUCT_FORMATTER =
+            findConstructorMethodHandle(Formatter.class, methodType(void.class, Appendable.class))
+                    .asType(methodType(Formatter.class, Appendable.class));
+    private static final MethodHandle CONSTRUCT_FORMATTER_EMPTY =
+            findConstructorMethodHandle(Formatter.class, methodType(void.class))
+                    .asType(methodType(Formatter.class));
+    private static final MethodHandle CONSTRUCT_FORMATTER_LOCALE =
+            findConstructorMethodHandle(Formatter.class, methodType(void.class, Locale.class))
+                    .asType(methodType(Formatter.class, Locale.class));
+
+    private static final MethodHandle CONSTRUCT_MISSING_FORMAT_ARGUMENT_EXCEPTION =
+            findConstructorMethodHandle(MissingFormatArgumentException.class, methodType(void.class, String.class));
+    private static final MethodHandle CONSTRUCT_ILLEGAL_FORMAT_CONVERSION_EXCEPTION =
+            findConstructorMethodHandle(IllegalFormatConversionException.class, methodType(void.class, char.class, Class.class));
+    private static final MethodHandle CONSTRUCT_UNKNOWN_FORMAT_CONVERSION_EXCEPTION =
+            findConstructorMethodHandle(UnknownFormatConversionException.class, methodType(void.class, String.class));
+    private static final MethodHandle OBJECT_TO_STRING =
+            findVirtualMethodHandle(Object.class, "toString", methodType(String.class));
+    private static final MethodHandle APPENDABLE_TO_STRING =
+            OBJECT_TO_STRING.asType(methodType(String.class, Appendable.class));
+    private static final MethodHandle FORMATTER_OUT =
+            findVirtualMethodHandle(Formatter.class, "out", methodType(Appendable.class));
+    private static final MethodHandle LOCALE_GETDEFAULT =
+            insertArguments(findStaticMethodHandle(Locale.class, "getDefault",
+                    methodType(Locale.class, Locale.Category.class)),0, Locale.Category.FORMAT);
+    private static final MethodHandle FORMATTER_LOCALE =
+            findVirtualMethodHandle(Formatter.class, "locale", methodType(Locale.class));
+
+    private static final MethodHandle BOOLEAN_TO_STRING =
+            findStaticMethodHandle(Boolean.class, "toString", methodType(String.class, boolean.class));
+    private static final MethodHandle OBJECT_HASHCODE =
+            findVirtualMethodHandle(Object.class, "hashCode", methodType(int.class));
+    private static final MethodHandle INTEGER_TO_HEX_STRING =
+            findStaticMethodHandle(Integer.class, "toHexString", methodType(String.class, int.class));
+    private static final MethodHandle INTEGER_TO_OCTAL_STRING =
+            findStaticMethodHandle(Integer.class, "toOctalString", methodType(String.class, int.class));
+    private static final MethodHandle STRING_TO_UPPER_CASE =
+            findVirtualMethodHandle(String.class, "toUpperCase", methodType(String.class));
+
+    private static final MethodHandle TOSTRING_RESET = findStaticMethodHandle(FormatterBootstraps.class, "toStringReset",
+            methodType(String.class, Formatter.class));
+    private static final MethodHandle LOCALE_GUARD = findStaticMethodHandle(FormatterBootstraps.class, "localeGuard",
+            methodType(boolean.class, Locale.class, Locale.class));
+    private static final MethodHandle BOOLEAN_OBJECT_FILTER = findStaticMethodHandle(FormatterBootstraps.class, "booleanObjectFilter",
+            methodType(boolean.class, Object.class));
+    private static final MethodHandle NOT_NULL_TEST = findStaticMethodHandle(FormatterBootstraps.class, "notNullTest",
+            methodType(boolean.class, Object.class));
+
+    private static final int MISSING_ARGUMENT_INDEX = Integer.MIN_VALUE;
+
+    /**
+     * Bootstrap for Formatter intrinsics.
+     * @param lookup         MethodHandles lookup
+     * @param name           Name of method
+     * @param methodType     Method signature
+     * @param format         Formatter format string
+     * @param isStringMethod Called from String method
+     * @param hasLocaleArg   Has a Locale argument
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite formatterBootstrap(MethodHandles.Lookup lookup,
+                                       String name,
+                                       MethodType methodType,
+                                       String format,
+                                       boolean isStringMethod,
+                                       boolean hasLocaleArg)
+            throws StringConcatException {
+        Formatter.CompiledFormat compiledFormat;
+
+        try {
+            compiledFormat = Formatter.compile(format);
+        } catch (UnknownFormatConversionException unknownConversion) {
+            return new ConstantCallSite(unknownFormatConversionThrower(unknownConversion, methodType));
+        }
+
+        List<Formatter.Specifier> specs = compiledFormat.specifiers();
+
+        if (specs.isEmpty()) {
+            return new ConstantCallSite(isStringMethod ?
+                    constant(String.class, "").asType(methodType) :
+                    identity(methodType.parameterType(0)).asType(methodType));
+        }
+
+        // Array of formatter args excluding target and locale
+        Class<?>[] argTypes = methodType.dropParameterTypes(0, firstFormatterArg(isStringMethod, hasLocaleArg)).ptypes();
+        // index array is needed because arg indexes are calculated forward but our method handle is composed backwards
+        int[] argIndexes = calculateArgumentIndexes(specs, argTypes.length);
+        boolean isFormatterMethod = methodType.parameterCount() > 0 && methodType.parameterType(0) == Formatter.class;
+
+        if ("true".equals(System.getProperty("formatter.stringconcat", "true"))) {
+            return makeStringConcatCallSite(lookup, name, methodType, specs, argTypes, argIndexes, hasLocaleArg, isStringMethod, isFormatterMethod);
+        }
+
+        return makeFormatterCallSite(methodType, specs, argTypes, argIndexes, hasLocaleArg, isStringMethod, isFormatterMethod);
+    }
+
+    private static CallSite makeStringConcatCallSite(MethodHandles.Lookup lookup, String name, MethodType methodType,
+                                                     List<Formatter.Specifier> specs, Class<?>[] argTypes, int[] argIndexes,
+                                                     boolean hasLocaleArg, boolean isStringMethod, boolean isFormatterMethod)
+                                        throws StringConcatException {
+        if (isStringMethod) {
+            return new ConstantCallSite(
+                    makeStringConcatHandle(lookup, name, methodType, specs, argTypes, argIndexes, hasLocaleArg, true));
+        }
+
+        if (!isFormatterMethod) {
+            Class<?> type = methodType.returnType();
+            MethodType formatterType = methodType.dropParameterTypes(0, 1).changeReturnType(String.class);
+            MethodHandle formatterHandle = makeStringConcatHandle(lookup, name,
+                    methodType(String.class, formatterType.ptypes()), specs, argTypes,
+                    argIndexes, hasLocaleArg, true);
+
+            MethodHandle identityHandle = dropArguments(identity(type), 1, formatterType.ptypes());
+            MethodHandle appenderHandle = dropArguments(APPENDABLE_APPEND.asType(methodType(void.class, type, String.class)), 2, formatterType.ptypes());
+            appenderHandle = foldArguments(appenderHandle, 1, formatterHandle);
+            identityHandle = foldArguments(identityHandle, 0, appenderHandle);
+            return new ConstantCallSite((identityHandle.asType(methodType)));
+        }
+
+        MethodType formatterType = methodType.dropParameterTypes(0, 1).changeReturnType(String.class);
+        if (!hasLocaleArg) {
+            formatterType = formatterType.insertParameterTypes(0, Locale.class);
+        }
+        MethodHandle formatterHandle = makeStringConcatHandle(lookup, name,
+                methodType(String.class, formatterType.ptypes()), specs, argTypes,
+                argIndexes, true, true);
+
+        MethodHandle identityHandle = dropArguments(identity(Formatter.class), 1, formatterType.ptypes());
+        MethodHandle appenderHandle = dropArguments(filterArgument(APPENDABLE_APPEND, 0, FORMATTER_OUT).asType(methodType(void.class, Formatter.class, String.class)), 2, formatterType.ptypes());
+        appenderHandle = foldArguments(appenderHandle, 1, formatterHandle);
+        identityHandle = foldArguments(identityHandle, 0, appenderHandle);
+        if (!hasLocaleArg) {
+            identityHandle = foldArguments(identityHandle, 1, FORMATTER_LOCALE, 0);
+        }
+        return new ConstantCallSite((identityHandle.asType(methodType)));
+    }
+
+    private static CallSite makeFormatterCallSite(MethodType methodType, List<Formatter.Specifier> specs,
+                                                  Class<?>[] argTypes, int[] argIndexes, boolean hasLocaleArg,
+                                                  boolean isStringMethod, boolean isFormatterMethod) {
+        MethodHandle handle = null;
+
+        // Reverse loop to compose method handle
+        for (int i = specs.size() - 1; i >= 0; i--) {
+            if (argIndexes[i] == -1) {
+                handle = addConstantMethodHandle(handle, argTypes, specs.get(i));
+            } else if (argIndexes[i] == MISSING_ARGUMENT_INDEX) {
+                handle = addMissingArgumentMethodHandle(handle, argTypes, specs.get(i));
+            } else {
+                handle = addMethodHandle(handle, argTypes, specs.get(i), argIndexes[i]);
+            }
+        }
+
+        handle = wrapFormatter(handle, methodType, hasLocaleArg, isStringMethod, isFormatterMethod);
+
+        return new ConstantCallSite(handle.asType(methodType));
+    }
+
+    private static int firstFormatterArg(boolean isStringMethod, boolean hasLocaleArg) {
+        int index = isStringMethod ? 0 : 1;
+        return hasLocaleArg ? index + 1 : index;
+    }
+
+    private static int[] calculateArgumentIndexes(List<Formatter.Specifier> specs, int argCount) {
+        int[] argIndexes = new int[specs.size()];
+        int last = -1;
+        int lasto = -1;
+
+        // Forward loop to calculate indices and throw exceptions for missing arguments
+        for (int i = 0; i < specs.size(); i++) {
+            Formatter.Specifier spec = specs.get(i);
+            int index = spec.index();
+            switch (index) {
+                case -2:  // fixed string, "%n", or "%%"
+                    argIndexes[i] = -1;
+                    break;
+                case -1:  // relative index
+                    argIndexes[i] = (last < 0 || last >= argCount) ? MISSING_ARGUMENT_INDEX : last;
+                    break;
+                case 0:  // ordinary index
+                    lasto++;
+                    last = lasto;
+                    argIndexes[i] = (last < 0 || last >= argCount) ? MISSING_ARGUMENT_INDEX : last;
+                    break;
+                default:  // explicit index
+                    last = index - 1;
+                    argIndexes[i] = (last < 0 || last >= argCount) ? MISSING_ARGUMENT_INDEX : last;
+                    break;
+            }
+        }
+
+        return argIndexes;
+    }
+
+
+    private static MethodHandle findVirtualMethodHandle(String className, String methodName, MethodType methodType) {
+        try {
+            return findVirtualMethodHandle(Class.forName(className), methodName, methodType);
+        } catch (ClassNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static MethodHandle findVirtualMethodHandle(Class<?> type, String name, MethodType methodType) {
+        try {
+            return IMPL_LOOKUP.findVirtual(type, name, methodType);
+        } catch (NoSuchMethodException | IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static MethodHandle findStaticMethodHandle(Class<?> type, String name, MethodType methodType) {
+        try {
+            return IMPL_LOOKUP.findStatic(type, name, methodType);
+        } catch (NoSuchMethodException | IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static MethodHandle findConstructorMethodHandle(Class<?> type, MethodType methodType) {
+        try {
+            return IMPL_LOOKUP.findConstructor(type, methodType);
+        } catch (NoSuchMethodException | IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static MethodHandle addMethodHandle(MethodHandle handle, Class<?>[] argTypes, Formatter.Specifier spec, int index) {
+
+        MethodHandle appender;
+
+        if (spec.hasEmptyFlags() && !requiresLocalization(spec) && argTypes[index].isPrimitive()) {
+            MethodHandle conversionFilter = getDirectConversionFilter(spec, argTypes[index]);
+            appender = filterArgument(SPECIFIER_PRINT_STRING, 2, conversionFilter);
+
+        } else {
+            appender = getPrintHandle(argTypes[index], spec);
+        }
+
+        appender = insertArguments(appender, 0, spec);
+        appender = appender.asType(appender.type().changeParameterType(1, argTypes[index]));
+
+        if (handle == null) {
+            if (index > 0) {
+                appender = dropArguments(appender, 1, Arrays.copyOfRange(argTypes, 0, index));
+            }
+            if (index < argTypes.length - 1) {
+                appender = dropArguments(appender, index + 2, Arrays.copyOfRange(argTypes, index + 1, argTypes.length));
+            }
+            return appender;
+        }
+
+        appender = appender.asType(appender.type().changeReturnType(void.class));
+        return foldArguments(handle, 0, appender,
+                0, index + 1, argTypes.length + 1);
+    }
+
+
+    private static MethodHandle addMissingArgumentMethodHandle(MethodHandle handle, Class<?>[] argTypes, Formatter.Specifier spec) {
+        MethodHandle thrower = missingFormatArgumentThrower(spec.toString());
+        if (handle == null) {
+            thrower = dropArguments(thrower, 0, Formatter.class);
+            thrower = dropArguments(thrower, 1, argTypes);
+            thrower = dropArguments(thrower, thrower.type().parameterCount(), Locale.class);
+            return thrower;
+        }
+
+        thrower = thrower.asType(thrower.type().changeReturnType(void.class));
+
+        return foldArguments(handle, 0, thrower);
+    }
+
+
+    private static MethodHandle addConstantMethodHandle(MethodHandle handle, Class<?>[] argTypes, Formatter.Specifier spec) {
+        MethodHandle appender = insertArguments(SPECIFIER_PRINT, 0, spec);
+        appender = insertArguments(appender, 1, (Object) null);
+
+        if (handle == null) {
+            return dropArguments(appender, 1, Arrays.copyOfRange(argTypes, 0, argTypes.length));
+        }
+        return foldArguments(handle, 0, appender.asType(appender.type().changeReturnType(void.class)),
+                0, argTypes.length + 1);
+    }
+
+
+    private static MethodHandle wrapFormatter(MethodHandle handle, MethodType methodType, boolean hasLocaleArg,
+                                              boolean isStringMethod, boolean isFormatterMethod) {
+        MethodHandle wrapper;
+        if (isFormatterMethod) {
+            wrapper = handle;
+        } else {
+            if (isStringMethod) {
+                wrapper = foldArguments(handle, 0, CONSTRUCT_FORMATTER_EMPTY);
+            } else {
+                wrapper = filterArgument(handle, 0, CONSTRUCT_FORMATTER);
+            }
+            wrapper = filterReturnValue(wrapper, FORMATTER_OUT);
+        }
+
+        if (hasLocaleArg) {
+            int[] argmap = new int[methodType.parameterCount()];
+            if (!isStringMethod) {
+                argmap[0] = 0;
+                argmap[argmap.length - 1] = 1;
+                for (int i = 1; i < argmap.length - 1; i++) {
+                    argmap[i] = i + 1;
+                }
+            } else {
+                argmap[argmap.length - 1] = 0;
+                for (int i = 0; i < argmap.length - 1; i++) {
+                    argmap[i] = i + 1;
+                }
+            }
+            MethodType newType = methodType.changeReturnType(wrapper.type().returnType());
+            if (!isStringMethod) {
+                newType = newType.changeParameterType(0, wrapper.type().parameterType(0));
+            }
+            wrapper = MethodHandles.permuteArguments(wrapper, newType, argmap);
+        } else {
+            if (isFormatterMethod) {
+                wrapper = foldArguments(wrapper, methodType.parameterCount(), FORMATTER_LOCALE, 0);
+            } else {
+                wrapper = foldArguments(wrapper, methodType.parameterCount(), LOCALE_GETDEFAULT);
+            }
+        }
+        return isStringMethod ? filterReturnValue(wrapper, APPENDABLE_TO_STRING) : wrapper;
+    }
+
+    private static MethodHandle missingFormatArgumentThrower(String message) {
+        MethodHandle thrower = throwException(Appendable.class, MissingFormatArgumentException.class);
+        return foldArguments(thrower, insertArguments(CONSTRUCT_MISSING_FORMAT_ARGUMENT_EXCEPTION, 0, message));
+    }
+
+    private static MethodHandle unknownFormatConversionThrower(UnknownFormatConversionException unknownFormat, MethodType methodType) {
+        MethodHandle thrower = throwException(methodType.returnType(), UnknownFormatConversionException.class);
+        thrower = foldArguments(thrower, insertArguments(CONSTRUCT_UNKNOWN_FORMAT_CONVERSION_EXCEPTION, 0, unknownFormat.getConversion()));
+        return dropArguments(thrower, 0, methodType.parameterArray());
+    }
+
+    private static MethodHandle illegalFormatConversionThrower(char conversion, Class<?> type, MethodType methodType) {
+        MethodHandle thrower = throwException(methodType.returnType(), IllegalFormatConversionException.class);
+        thrower = foldArguments(thrower, insertArguments(CONSTRUCT_ILLEGAL_FORMAT_CONVERSION_EXCEPTION, 0, conversion, type));
+        thrower = dropArguments(thrower, 0, methodType.parameterArray());
+        return thrower;
+    }
+
+    private static Appendable append(Appendable appendable, CharSequence cs) throws IOException {
+        return appendable.append(cs);
+    }
+
+    private static String toStringReset(Formatter formatter) {
+        String str = formatter.out().toString();
+        ((StringBuilder) formatter.out()).setLength(0);
+        return str;
+    }
+
+    private static boolean localeGuard(Locale locale1, Locale locale2) {
+        return locale1 == locale2;
+    }
+
+    private static boolean booleanObjectFilter(Object arg) {
+        return arg != null && (! (arg instanceof Boolean) || ((Boolean) arg));
+    }
+
+    private static boolean notNullTest(Object arg) {
+        return arg != null;
+    }
+
+    private static MethodHandle makeStringConcatHandle(MethodHandles.Lookup lookup, String name, MethodType callsiteType,
+                                                     List<Formatter.Specifier> specs, Class<?>[] argTypes, int[] argIndexes,
+                                                     boolean hasLocaleArg, boolean useConcat) throws StringConcatException {
+        List<Object> constants = new ArrayList<>();
+        List<Integer> reorder = new ArrayList<>();
+        MethodType concatType = methodType(String.class);
+        StringBuilder recipe = new StringBuilder();
+        boolean needsFormatter = false;
+        boolean needsLocaleGuard = false;
+
+        for (int i = 0; i < argIndexes.length; i++) {
+            Formatter.Specifier spec = specs.get(i);
+            if (argIndexes[i] == -1) {
+                char conversion = spec.conversion();
+                if (conversion == 'n') {
+                    recipe.append(System.lineSeparator());
+                } else if (conversion == '%') {
+                    recipe.append(String.format(spec.toString()));
+                } else {
+                    String str = spec.toString();
+                    if (str.length() == 1 && str.charAt(0) > 1) {
+                        recipe.append(str);
+                    } else if (str.length() > 1) {
+                        recipe.append('\2');
+                        constants.add(spec.toString());
+                    }
+                }
+            } else if (argIndexes[i] != MISSING_ARGUMENT_INDEX) {
+                recipe.append('\1');
+                int index = argIndexes[i];
+                boolean isConcat = useConcat && useStringConcat(spec, argTypes[index]);
+                concatType = concatType.appendParameterTypes(isConcat ? argTypes[index] : String.class);
+                reorder.add(index);
+            }
+        }
+
+
+        CallSite cs = StringConcatFactory.makeConcatWithConstants(lookup, name, concatType, recipe.toString(), constants.toArray());
+
+        MethodHandle handle = dropArguments(cs.getTarget(), 0, Formatter.class, Locale.class);
+        int paramIndex = 2;
+
+        for (int i = 0; i < argIndexes.length; i++) {
+            if (argIndexes[i] == -1) {
+                continue;
+            }
+
+            if (argIndexes[i] == MISSING_ARGUMENT_INDEX) {
+                MethodHandle thrower = throwException(void.class, MissingFormatArgumentException.class);
+                thrower = foldArguments(thrower, insertArguments(CONSTRUCT_MISSING_FORMAT_ARGUMENT_EXCEPTION, 0, specs.get(i).toString()));
+                handle = foldArguments(handle, 3, thrower);
+            } else {
+                Formatter.Specifier spec = specs.get(i);
+                Class<?> argType = argTypes[argIndexes[i]];
+
+                if (!useConcat || !useStringConcat(spec, argType)) {
+
+                    if (spec.hasEmptyFlags() && !requiresLocalization(spec) && argType.isPrimitive()) {
+                        // Direct handle requiring no formatter or localization
+                        MethodHandle conversionFilter = getDirectConversionFilter(spec, argType);
+                        handle = filterArgument(handle, paramIndex, conversionFilter);
+
+                    } else {
+                        // Use handle from java.util.Formatter with full localization support
+                        MethodHandle combiner = getPrintHandle(argType, spec);
+                        combiner = combiner.asType(combiner.type().changeParameterType(2, argType));
+                        combiner = insertArguments(combiner, 0, specs.get(i));
+                        combiner = filterReturnValue(combiner, TOSTRING_RESET);
+                        handle = dropArguments(handle, paramIndex, argType);
+                        handle = foldArguments(handle, paramIndex + 1, combiner, 0, paramIndex, 1);
+                        needsFormatter = true;
+                    }
+
+                } else if (spec.conversion() == 'd') {
+                    // Direct string concat, but we need to guard against locales requiring Unicode symbols
+                    needsLocaleGuard = true;
+                }
+            }
+            paramIndex++;
+
+        }
+
+        if (needsFormatter) {
+            handle = foldArguments(handle, 0, CONSTRUCT_FORMATTER_LOCALE);
+        } else {
+            handle = insertArguments(handle, 0, (Object) null);
+        }
+
+        if (!useConcat) {
+            return handle;
+        }
+
+        if (!needsFormatter && needsLocaleGuard) {
+            // We have a decimal int without formatter - this doesn't work for
+            // locales using unicode decimal symbols, so add a guard and fallback handle for that case
+            Locale defaultLocale = Locale.getDefault(Locale.Category.FORMAT);
+            if (defaultLocale == null || DecimalFormatSymbols.getInstance(defaultLocale).getZeroDigit() != '0') {
+                defaultLocale = Locale.US;
+            }
+            handle = MethodHandles.guardWithTest(
+                    insertArguments(LOCALE_GUARD, 0, defaultLocale),
+                    handle,
+                    makeStringConcatHandle(lookup, name, callsiteType, specs, argTypes, argIndexes, hasLocaleArg, false));
+        }
+
+        if (!hasLocaleArg) {
+            handle = foldArguments(handle, 0, LOCALE_GETDEFAULT);
+        }
+
+        int[] reorderArray = hasLocaleArg ?
+                // Leading Locale arg - add initial element to keep it in place and increase other values by 1
+                IntStream.concat(IntStream.of(0), reorder.stream().mapToInt(i -> i + 1)).toArray() :
+                reorder.stream().mapToInt(i -> i).toArray();
+
+
+        return MethodHandles.permuteArguments(handle, callsiteType, reorderArray);
+    }
+
+    private static MethodHandle getDirectConversionFilter(Formatter.Specifier spec, Class<?> argType) {
+        MethodHandle conversionFilter;
+
+        switch (spec.conversion()) {
+            case 'h':
+                conversionFilter = filterArgument(INTEGER_TO_HEX_STRING, 0, OBJECT_HASHCODE);
+                break;
+            case 'd':
+                conversionFilter = INT_TO_STRING;
+                break;
+            case 'x':
+                conversionFilter = INTEGER_TO_HEX_STRING;
+                break;
+            case 'o':
+                conversionFilter = INTEGER_TO_OCTAL_STRING;
+                break;
+            case 'b':
+                conversionFilter = BOOLEAN_TO_STRING;
+                break;
+            default:
+                throw new IllegalStateException("Unexpected conversion: " + spec.conversion());
+        }
+
+        if (conversionFilter.type().parameterType(0) != argType) {
+            if (spec.conversion() == 'b')
+                conversionFilter = filterArgument(conversionFilter, 0, BOOLEAN_OBJECT_FILTER);
+            else if (! argType.isPrimitive())
+                conversionFilter = guardWithTest(NOT_NULL_TEST,
+                        conversionFilter.asType(methodType(String.class, Object.class)),
+                        dropArguments(constant(String.class, "null"), 0, Object.class));
+            conversionFilter = conversionFilter.asType(conversionFilter.type().changeParameterType(0, argType));
+        }
+
+        if (spec.isUpperCase()) {
+            conversionFilter = filterArgument(STRING_TO_UPPER_CASE,0, conversionFilter);
+        }
+
+        return conversionFilter;
+    }
+
+    private static boolean isSafeArgumentType(char conversion, Class<?> type) {
+        if (conversion == 'd') {
+            return type == int.class || type == long.class || type == short.class || type == byte.class ||
+                    type == Integer.class || type == Long.class || type == Short.class || type == Byte.class;
+        }
+        return true;
+    }
+
+    private static boolean useStringConcat(Formatter.Specifier spec, Class<?> argType) {
+        return spec.hasEmptyFlags()
+                && !spec.isUpperCase()
+                && !spec.isDateTime()
+                && "sdn%".indexOf(spec.conversion()) >= 0
+                && isSafeArgumentType(spec.conversion(), argType);
+    }
+
+    private static boolean requiresLocalization(Formatter.Specifier spec) {
+        return spec.isDateTime() || "bxon%".indexOf(spec.conversion()) < 0;
+    }
+
+    private static MethodHandle getPrintHandle(Class<?> argType, Formatter.Specifier spec) {
+        if (spec.conversion() == 'h' && !spec.isDateTime()) {
+            return SPECIFIER_PRINT_HASHCODE;
+        } else if (argType == int.class) {
+            return SPECIFIER_PRINT_INT;
+        } else if (argType == long.class) {
+            return SPECIFIER_PRINT_LONG;
+        } else if (argType == byte.class) {
+            return SPECIFIER_PRINT_BYTE;
+        } else if (argType == short.class) {
+            return SPECIFIER_PRINT_SHORT;
+        } else if (argType == float.class) {
+            return SPECIFIER_PRINT_FLOAT;
+        } else if (argType == double.class) {
+            return SPECIFIER_PRINT_DOUBLE;
+        } else {
+            return SPECIFIER_PRINT;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/invoke/IntrinsicFactory.java	Wed Oct 31 11:08:50 2018 -0300
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+package java.lang.invoke;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Locale;
+import java.util.MissingFormatArgumentException;
+import java.util.stream.IntStream;
+
+/**
+ * Bootstrapping support for Intrinsics.
+ */
+public final class IntrinsicFactory {
+    /**
+     * formatterFormatBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite formatterFormatBootstrap(MethodHandles.Lookup lookup,
+                                                    String name,
+                                                    MethodType methodType,
+                                                    String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, false, false);
+    }
+
+    /**
+     * formatterLocaleFormatBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite formatterLocaleFormatBootstrap(MethodHandles.Lookup lookup,
+                                                          String name,
+                                                          MethodType methodType,
+                                                          String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, false, true);
+    }
+
+    /**
+     * printStreamFormatBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite printStreamFormatBootstrap(MethodHandles.Lookup lookup,
+                                                      String name,
+                                                      MethodType methodType,
+                                                      String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, false, false);
+    }
+
+    /**
+     * printStreamLocaleFormatBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite printStreamLocaleFormatBootstrap(MethodHandles.Lookup lookup,
+                                                            String name,
+                                                            MethodType methodType,
+                                                            String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, false, true);
+    }
+
+    /**
+     * printStreamPrintfBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite printStreamPrintfBootstrap(MethodHandles.Lookup lookup,
+                                                      String name,
+                                                      MethodType methodType,
+                                                      String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, false, false);
+    }
+
+    /**
+     * printStreamLocalePrintfBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite printStreamLocalePrintfBootstrap(MethodHandles.Lookup lookup,
+                                                            String name,
+                                                            MethodType methodType,
+                                                            String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, false, true);
+    }
+
+    /**
+     * printWriterFormatBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite printWriterFormatBootstrap(MethodHandles.Lookup lookup,
+                                                      String name,
+                                                      MethodType methodType,
+                                                      String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, false, false);
+    }
+
+    /**
+     * printWriterLocaleFormatBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite printWriterLocaleFormatBootstrap(MethodHandles.Lookup lookup,
+                                                            String name,
+                                                            MethodType methodType,
+                                                            String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, false, true);
+    }
+
+    /**
+     * printWriterPrintfBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite printWriterPrintfBootstrap(MethodHandles.Lookup lookup,
+                                                      String name,
+                                                      MethodType methodType,
+                                                      String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, false, false);
+    }
+
+    /**
+     * printWriterLocalePrintfBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite printWriterLocalePrintfBootstrap(MethodHandles.Lookup lookup,
+                                                            String name,
+                                                            MethodType methodType,
+                                                            String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, false, true);
+    }
+
+    /**
+     * staticStringFormatBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite staticStringFormatBootstrap(MethodHandles.Lookup lookup,
+                                                       String name,
+                                                       MethodType methodType,
+                                                       String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, true, false);
+    }
+
+    /**
+     * staticStringLocaleFormatBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite staticStringLocaleFormatBootstrap(MethodHandles.Lookup lookup,
+                                                             String name,
+                                                             MethodType methodType,
+                                                             String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, true, true);
+    }
+
+    /**
+     * stringFormatBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite stringFormatBootstrap(MethodHandles.Lookup lookup,
+                                                 String name,
+                                                 MethodType methodType,
+                                                 String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, true, false);
+    }
+
+    /**
+     * stringLocaleFormatBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite stringLocaleFormatBootstrap(MethodHandles.Lookup lookup,
+                                                       String name,
+                                                       MethodType methodType,
+                                                       String format)
+            throws NoSuchMethodException, IllegalAccessException, StringConcatException {
+        return FormatterBootstraps.formatterBootstrap(lookup, name, methodType, format, true, true);
+    }
+
+    /**
+     * objectsHashBootstrap bootstrap.
+     * @param lookup      MethodHandles lookup
+     * @param name        Name of method
+     * @param methodType  Method signature
+     * @param format      Formatter format string
+     * @throws NoSuchMethodException no such method
+     * @throws IllegalAccessException illegal access
+     * @throws StringConcatException string concat error
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite objectsHashBootstrap(MethodHandles.Lookup lookup,
+                                                String name,
+                                                MethodType methodType)
+            throws NoSuchMethodException, IllegalAccessException {
+        return ObjectsBootstraps.hashBootstrap(lookup, name, methodType);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/invoke/ObjectsBootstraps.java	Wed Oct 31 11:08:50 2018 -0300
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+package java.lang.invoke;
+
+import java.lang.invoke.ConstantCallSite;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
+import java.util.HashMap;
+import java.util.Map;
+
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+
+/**
+ * Bootstrapping support for Objects intrinsics.
+ */
+public final class ObjectsBootstraps {
+    /**
+     * Bootstrap for Objects intrinsics.
+     * @param lookup         MethodHandles lookup
+     * @param name           Name of method
+     * @param methodType     Method signature
+     * @return Callsite for intrinsic method
+     */
+    public static CallSite hashBootstrap(MethodHandles.Lookup lookup,
+                                         String name,
+                                         MethodType methodType) {
+        assert methodType.returnType() == int.class;
+        initialize();
+        return new ConstantCallSite(createHashMethodHandle(methodType.parameterArray()));
+    }
+
+    static Map<Class<?>, MethodHandle> HASH_METHODS;
+    static MethodHandle HASH_OBJECT;
+
+    static void initialize() {
+        if (HASH_METHODS == null) {
+            HASH_METHODS = new HashMap<>();
+            HASH_METHODS.put(boolean.class, findHashMethod(boolean.class));
+            HASH_METHODS.put(byte.class, findHashMethod(byte.class));
+            HASH_METHODS.put(char.class, findHashMethod(char.class));
+            HASH_METHODS.put(short.class, findHashMethod(short.class));
+            HASH_METHODS.put(int.class, findHashMethod(int.class));
+            HASH_METHODS.put(float.class, findHashMethod(float.class));
+            HASH_METHODS.put(double.class, findHashMethod(double.class));
+
+            HASH_OBJECT = findHashMethod(Object.class);
+        }
+    }
+
+    static MethodHandle createHashMethodHandle(Class<?>... argTypes) {
+        MethodHandle hashMH = MethodHandles.constant(int.class, 1);
+
+        if (argTypes.length != 0) {
+            MethodType methodType = MethodType.methodType(int.class, argTypes);
+            hashMH = MethodHandles.permuteArguments(hashMH, methodType, new int[]{});
+            methodType = methodType.insertParameterTypes(0, int.class);
+
+            for (int i = 0; i < argTypes.length; i++) {
+                MethodHandle argMH = getHashMethod(argTypes[i]);
+                argMH = MethodHandles.permuteArguments(argMH, methodType, new int[]{0, i + 1});
+                hashMH = MethodHandles.foldArguments(argMH, hashMH);
+            }
+        }
+
+        return hashMH;
+    }
+
+    static MethodHandle getHashMethod(Class<?> type) {
+        MethodHandle hashMH = HASH_METHODS.get(type);
+        if (hashMH == null) {
+            hashMH = HASH_OBJECT;
+            hashMH = hashMH.asType(MethodType.methodType(int.class, int.class, type));
+        }
+        return hashMH;
+    }
+
+    static MethodHandle findHashMethod(Class<?> cls) {
+        try {
+            MethodType mt = MethodType.methodType(int.class, int.class, cls);
+            return IMPL_LOOKUP.findStatic(ObjectsBootstraps.class, "hash", mt);
+        } catch (NoSuchMethodException | IllegalAccessException ex) {
+            return null;
+        }
+     }
+
+    static int hash(int result, boolean value) {
+        return 31 * result + Boolean.hashCode(value);
+    }
+
+    static int hash(int result, char value) {
+        return 31 * result + Character.hashCode(value);
+    }
+
+    static int hash(int result, byte value) {
+        return 31 * result + Byte.hashCode(value);
+    }
+
+    static int hash(int result, short value) {
+        return 31 * result + Short.hashCode(value);
+    }
+
+    static int hash(int result, int value) {
+        return 31 * result + Integer.hashCode(value);
+    }
+
+    static int hash(int result, float value) {
+        return 31 * result + Float.hashCode(value);
+    }
+
+    static int hash(int result, double value) {
+        return 31 * result + Double.hashCode(value);
+    }
+
+    static int hash(int result, Object value) {
+        return 31 * result + (value == null ? 0 : value.hashCode());
+    }
+}
--- a/src/java.base/share/classes/java/util/Formatter.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/src/java.base/share/classes/java/util/Formatter.java	Wed Oct 31 11:08:50 2018 -0300
@@ -61,6 +61,7 @@
 import java.time.temporal.TemporalQueries;
 import java.time.temporal.UnsupportedTemporalTypeException;
 
+import java.lang.compiler.IntrinsicCandidate;
 import jdk.internal.math.DoubleConsts;
 import jdk.internal.math.FormattedFloatingDecimal;
 import sun.util.locale.provider.LocaleProviderAdapter;
@@ -1913,17 +1914,21 @@
  * @since 1.5
  */
 public final class Formatter implements Closeable, Flushable {
-    private Appendable a;
-    private final Locale l;
-
-    private IOException lastException;
-
-    private final char zero;
-    private static double scaleUp;
-
-    // 1 (sign) + 19 (max # sig digits) + 1 ('.') + 1 ('e') + 1 (sign)
-    // + 3 (max # exp digits) + 4 (error) = 30
-    private static final int MAX_FD_CHARS = 30;
+    /** Receiving Appendable */
+    Appendable a;
+    /** Formatter locale */
+    final Locale l;
+    /** Last low level exception caught */
+    IOException lastException;
+    /** Zero for the locale */
+    final char zero;
+    /** Round up scaler */
+    static double SCALEUP = Math.scalb(1.0, 54);
+    /** Maximum floating decimal digits
+     *    1 (sign) + 19 (max # sig digits) + 1 ('.') + 1 ('e') + 1 (sign)
+     *    + 3 (max # exp digits) + 4 (error) = 30
+     */
+    static final int MAX_FD_CHARS = 30;
 
     /**
      * Returns a charset object for the given charset name.
@@ -2441,6 +2446,10 @@
         }
     }
 
+    private boolean usesDefaultZero(Locale l) {
+        return zero == '0' && (l == null || l.equals(this.l) || l.equals(Locale.US));
+    }
+
     /**
      * Returns the locale set by the construction of this formatter.
      *
@@ -2605,6 +2614,7 @@
      *
      * @return  This formatter
      */
+    @IntrinsicCandidate
     public Formatter format(String format, Object ... args) {
         return format(l, format, args);
     }
@@ -2644,7 +2654,14 @@
      *
      * @return  This formatter
      */
+    @IntrinsicCandidate
     public Formatter format(Locale l, String format, Object ... args) {
+        List<Specifier> fsa = parse(format);
+        format(l, fsa, args);
+        return this;
+    }
+
+    void format(Locale l, List<Specifier> fsa, Object ... args) {
         ensureOpen();
 
         // index of last argument referenced
@@ -2652,38 +2669,106 @@
         // last ordinary index
         int lasto = -1;
 
-        List<FormatString> fsa = parse(format);
-        for (FormatString fs : fsa) {
+        for (Specifier fs : fsa) {
             int index = fs.index();
             try {
                 switch (index) {
                 case -2:  // fixed string, "%n", or "%%"
-                    fs.print(null, l);
+                    fs.print(this, null, l);
                     break;
                 case -1:  // relative index
                     if (last < 0 || (args != null && last > args.length - 1))
                         throw new MissingFormatArgumentException(fs.toString());
-                    fs.print((args == null ? null : args[last]), l);
+                    fs.print(this, (args == null ? null : args[last]), l);
                     break;
                 case 0:  // ordinary index
                     lasto++;
                     last = lasto;
                     if (args != null && lasto > args.length - 1)
                         throw new MissingFormatArgumentException(fs.toString());
-                    fs.print((args == null ? null : args[lasto]), l);
+                    fs.print(this, (args == null ? null : args[lasto]), l);
                     break;
                 default:  // explicit index
                     last = index - 1;
                     if (args != null && last > args.length - 1)
                         throw new MissingFormatArgumentException(fs.toString());
-                    fs.print((args == null ? null : args[last]), l);
+                    fs.print(this, (args == null ? null : args[last]), l);
                     break;
                 }
             } catch (IOException x) {
                 lastException = x;
             }
         }
-        return this;
+
+    }
+
+    /**
+     * Internal interface used to intrinsic-fy formatter usage.
+     */
+    public static class CompiledFormat {
+        private List<Specifier> specifiers;
+
+        private CompiledFormat(List<Specifier> specifiers) {
+            this.specifiers = specifiers;
+        }
+
+        /**
+         * Format the arguments using the compiled format.
+         * @param formatter formatter to use
+         * @param args      format arguments
+         * @return this CompiledFormat
+         */
+        public CompiledFormat format(Formatter formatter, Object... args) {
+            formatter.format(formatter.l, specifiers, args);
+            return this;
+        }
+
+        /**
+         * Format the arguments using the compiled format.
+         * @param formatter formatter to use
+         * @param locale locale to use with format
+         * @param args   format arguments
+         * @return this CompiledFormat
+         */
+        public CompiledFormat format(Formatter formatter, Locale locale, Object... args) {
+            formatter.format(locale, specifiers, args);
+            return this;
+        }
+
+        /**
+         * Returns the number of specifiers.
+         * @return number of specifiers.
+         */
+        public int count() {
+            return specifiers.size();
+        }
+
+        /**
+         * Returns a list of format specifier information.
+         * @return a list of format specifier information
+         */
+        public List<Specifier> specifiers() {
+            return new ArrayList<>(specifiers);
+        }
+
+        /**
+         * Returns the string from the wrapping
+         * @param formatter formatter to use
+         * @return formatter toString
+         */
+        public String toString(Formatter formatter) {
+            return formatter.toString();
+        }
+    }
+
+    /**
+     * Creates a compiled format object.
+     * @param format to compile
+     * @return a compiled format
+     */
+    public static CompiledFormat compile(String format) {
+        List<Specifier> specifiers = parse(format);
+        return new CompiledFormat(specifiers);
     }
 
     // %[argument_index$][flags][width][.precision][t]conversion
@@ -2695,8 +2780,8 @@
     /**
      * Finds format specifiers in the format string.
      */
-    private List<FormatString> parse(String s) {
-        ArrayList<FormatString> al = new ArrayList<>();
+    private static List<Specifier> parse(String s) {
+        ArrayList<Specifier> al = new ArrayList<>();
         Matcher m = fsPattern.matcher(s);
         for (int i = 0, len = s.length(); i < len; ) {
             if (m.find(i)) {
@@ -2734,13 +2819,68 @@
         }
     }
 
-    private interface FormatString {
+    private StringBuilder maybeNewStringBuilder(int width) {
+        return  width == -1 && a instanceof StringBuilder ? (StringBuilder) a : new StringBuilder();
+    }
+
+    /**
+     * Interface for Formatter specifiers.
+     */
+    public interface Specifier {
+        /**
+         * Return the specifier index.
+         * @return the index
+         */
         int index();
-        void print(Object arg, Locale l) throws IOException;
+
+        /**
+         * Print the specifier to the formatter's appendable.
+         * @param formatter the formatter
+         * @param arg the argument
+         * @param l the locale
+         * @return the formatter
+         * @throws IOException an error occurred
+         */
+        Formatter print(Formatter formatter, Object arg, Locale l) throws IOException;
+
+        /**
+         * Return the specifier value.
+         * @return the value
+         */
+        String value();
+
+        /**
+         * Return the conversion type.
+         * @return the conversion type
+         */
+        char conversion();
+
+        /**
+         * Return a string representation of the specifier.
+         * @return a string representation
+         */
         String toString();
+
+        /**
+         * Is this specifier has empty flags.
+         * @return true if flags are empty
+         */
+        boolean hasEmptyFlags();
+
+        /**
+         * Is this a date-time specifier?
+         * @return true if date-time specifier
+         */
+        boolean isDateTime();
+
+        /**
+         * is this an upper case sepcifier?
+         * @return true if upper case flag is set
+         */
+        boolean isUpperCase();
     }
 
-    private class FixedString implements FormatString {
+    private static class FixedString implements Specifier {
         private String s;
         private int start;
         private int end;
@@ -2750,9 +2890,16 @@
             this.end = end;
         }
         public int index() { return -2; }
-        public void print(Object arg, Locale l)
-            throws IOException { a.append(s, start, end); }
+        public Formatter print(Formatter formatter, Object arg, Locale l) throws IOException {
+            formatter.a.append(s, start, end);
+            return formatter;
+        }
+        public String value() { return toString(); }
+        public char conversion() { return '\0'; }
         public String toString() { return s.substring(start, end); }
+        public boolean hasEmptyFlags() { return true; }
+        public boolean isDateTime() { return false; }
+        public boolean isUpperCase() { return false; }
     }
 
     /**
@@ -2770,7 +2917,7 @@
         DECIMAL_FLOAT
     };
 
-    private class FormatSpecifier implements FormatString {
+    private static class FormatSpecifier implements Specifier {
         private int index = -1;
         private Flags f = Flags.NONE;
         private int width;
@@ -2778,6 +2925,14 @@
         private boolean dt = false;
         private char c;
 
+        public String value() {
+            return toString();
+        }
+
+        public char conversion() {
+            return c;
+        }
+
         private int index(String s, int start, int end) {
             if (start >= 0) {
                 try {
@@ -2880,80 +3035,94 @@
                 throw new UnknownFormatConversionException(String.valueOf(c));
         }
 
-        public void print(Object arg, Locale l) throws IOException {
+
+        public boolean hasEmptyFlags() {
+            return (f.isEmpty() || f.valueOf() == Flags.UPPERCASE.valueOf()) && width == -1;
+        }
+
+        public boolean isDateTime() {
+            return dt;
+        }
+
+        public boolean isUpperCase() {
+            return f.valueOf() == Flags.UPPERCASE.valueOf();
+        }
+
+        public Formatter print(Formatter formatter, Object arg, Locale l) throws IOException {
             if (dt) {
-                printDateTime(arg, l);
-                return;
+                printDateTime(formatter, arg, l);
+                return formatter;
             }
             switch(c) {
             case Conversion.DECIMAL_INTEGER:
             case Conversion.OCTAL_INTEGER:
             case Conversion.HEXADECIMAL_INTEGER:
-                printInteger(arg, l);
+                printInteger(formatter, arg, l);
                 break;
             case Conversion.SCIENTIFIC:
             case Conversion.GENERAL:
             case Conversion.DECIMAL_FLOAT:
             case Conversion.HEXADECIMAL_FLOAT:
-                printFloat(arg, l);
+                printFloat(formatter, arg, l);
                 break;
             case Conversion.CHARACTER:
             case Conversion.CHARACTER_UPPER:
-                printCharacter(arg, l);
+                printCharacter(formatter, arg, l);
                 break;
             case Conversion.BOOLEAN:
-                printBoolean(arg, l);
+                printBoolean(formatter, arg, l);
                 break;
             case Conversion.STRING:
-                printString(arg, l);
+                printString(formatter, arg, l);
                 break;
             case Conversion.HASHCODE:
-                printHashCode(arg, l);
+                printHashCode(formatter, arg, l);
                 break;
             case Conversion.LINE_SEPARATOR:
-                a.append(System.lineSeparator());
+                formatter.a.append(System.lineSeparator());
                 break;
             case Conversion.PERCENT_SIGN:
-                print("%", l);
+                print(formatter, "%", l);
                 break;
             default:
                 assert false;
             }
+            return formatter;
         }
 
-        private void printInteger(Object arg, Locale l) throws IOException {
+        private void printInteger(Formatter formatter, Object arg, Locale l) throws IOException {
             if (arg == null)
-                print("null", l);
+                print(formatter, "null", l);
             else if (arg instanceof Byte)
-                print(((Byte)arg).byteValue(), l);
+                print(formatter, ((Byte)arg).byteValue(), l);
             else if (arg instanceof Short)
-                print(((Short)arg).shortValue(), l);
+                print(formatter, ((Short)arg).shortValue(), l);
             else if (arg instanceof Integer)
-                print(((Integer)arg).intValue(), l);
+                print(formatter, ((Integer)arg).intValue(), l);
             else if (arg instanceof Long)
-                print(((Long)arg).longValue(), l);
+                print(formatter, ((Long)arg).longValue(), l);
             else if (arg instanceof BigInteger)
-                print(((BigInteger)arg), l);
+                print(formatter, ((BigInteger)arg), l);
             else
                 failConversion(c, arg);
         }
 
-        private void printFloat(Object arg, Locale l) throws IOException {
+        private void printFloat(Formatter formatter, Object arg, Locale l) throws IOException {
             if (arg == null)
-                print("null", l);
+                print(formatter, "null", l);
             else if (arg instanceof Float)
-                print(((Float)arg).floatValue(), l);
+                print(formatter, ((Float)arg).floatValue(), l);
             else if (arg instanceof Double)
-                print(((Double)arg).doubleValue(), l);
+                print(formatter, ((Double)arg).doubleValue(), l);
             else if (arg instanceof BigDecimal)
-                print(((BigDecimal)arg), l);
+                print(formatter, ((BigDecimal)arg), l);
             else
                 failConversion(c, arg);
         }
 
-        private void printDateTime(Object arg, Locale l) throws IOException {
+        void printDateTime(Formatter formatter, Object arg, Locale l) throws IOException {
             if (arg == null) {
-                print("null", l);
+                print(formatter, "null", l);
                 return;
             }
             Calendar cal = null;
@@ -2974,19 +3143,19 @@
                 cal = (Calendar) ((Calendar) arg).clone();
                 cal.setLenient(true);
             } else if (arg instanceof TemporalAccessor) {
-                print((TemporalAccessor) arg, c, l);
+                print(formatter, (TemporalAccessor) arg, c, l);
                 return;
             } else {
                 failConversion(c, arg);
             }
             // Use the provided locale so that invocations of
             // localizedMagnitude() use optimizations for null.
-            print(cal, c, l);
+            print(formatter, cal, c, l);
         }
 
-        private void printCharacter(Object arg, Locale l) throws IOException {
+        private void printCharacter(Formatter formatter, Object arg, Locale l) throws IOException {
             if (arg == null) {
-                print("null", l);
+                print(formatter, "null", l);
                 return;
             }
             String s = null;
@@ -3013,12 +3182,12 @@
             } else {
                 failConversion(c, arg);
             }
-            print(s, l);
+            print(formatter, s, l);
         }
 
-        private void printString(Object arg, Locale l) throws IOException {
+        private void printString(Formatter formatter, Object arg, Locale l) throws IOException {
             if (arg instanceof Formattable) {
-                Formatter fmt = Formatter.this;
+                Formatter fmt = formatter;
                 if (fmt.locale() != l)
                     fmt = new Formatter(fmt.out(), l);
                 ((Formattable)arg).formatTo(fmt, f.valueOf(), width, precision);
@@ -3026,13 +3195,13 @@
                 if (f.contains(Flags.ALTERNATE))
                     failMismatch(Flags.ALTERNATE, 's');
                 if (arg == null)
-                    print("null", l);
+                    print(formatter, "null", l);
                 else
-                    print(arg.toString(), l);
+                    print(formatter, arg.toString(), l);
             }
         }
 
-        private void printBoolean(Object arg, Locale l) throws IOException {
+        private void printBoolean(Formatter formatter, Object arg, Locale l) throws IOException {
             String s;
             if (arg != null)
                 s = ((arg instanceof Boolean)
@@ -3040,30 +3209,32 @@
                      : Boolean.toString(true));
             else
                 s = Boolean.toString(false);
-            print(s, l);
+            print(formatter, s, l);
         }
 
-        private void printHashCode(Object arg, Locale l) throws IOException {
+        private Formatter printHashCode(Formatter formatter, Object arg, Locale l) throws IOException {
             String s = (arg == null
                         ? "null"
                         : Integer.toHexString(arg.hashCode()));
-            print(s, l);
+            print(formatter, s, l);
+            return formatter;
         }
 
-        private void print(String s, Locale l) throws IOException {
+        Formatter print(Formatter formatter, String s, Locale l) throws IOException {
             if (precision != -1 && precision < s.length())
                 s = s.substring(0, precision);
             if (f.contains(Flags.UPPERCASE))
                 s = toUpperCaseWithLocale(s, l);
-            appendJustified(a, s);
+            appendJustified(formatter.a, s);
+            return formatter;
         }
 
-        private String toUpperCaseWithLocale(String s, Locale l) {
+        String toUpperCaseWithLocale(String s, Locale l) {
             return s.toUpperCase(Objects.requireNonNullElse(l,
                     Locale.getDefault(Locale.Category.FORMAT)));
         }
 
-        private Appendable appendJustified(Appendable a, CharSequence cs) throws IOException {
+        Appendable appendJustified(Appendable a, CharSequence cs) throws IOException {
              if (width == -1) {
                  return a.append(cs);
              }
@@ -3204,62 +3375,69 @@
             }
         }
 
-        private void print(byte value, Locale l) throws IOException {
+        private Formatter print(Formatter formatter, byte value, Locale l) throws IOException {
             long v = value;
             if (value < 0
-                && (c == Conversion.OCTAL_INTEGER
+                    && (c == Conversion.OCTAL_INTEGER
                     || c == Conversion.HEXADECIMAL_INTEGER)) {
                 v += (1L << 8);
                 assert v >= 0 : v;
             }
-            print(v, l);
+            return print(formatter, v, l);
         }
 
-        private void print(short value, Locale l) throws IOException {
+        private Formatter print(Formatter formatter, short value, Locale l) throws IOException {
             long v = value;
             if (value < 0
-                && (c == Conversion.OCTAL_INTEGER
+                    && (c == Conversion.OCTAL_INTEGER
                     || c == Conversion.HEXADECIMAL_INTEGER)) {
                 v += (1L << 16);
                 assert v >= 0 : v;
             }
-            print(v, l);
+            return print(formatter, v, l);
         }
 
-        private void print(int value, Locale l) throws IOException {
+        private Formatter print(Formatter formatter, int value, Locale l) throws IOException {
+
+            if (c == Conversion.DECIMAL_INTEGER && hasEmptyFlags() && !dt && formatter.usesDefaultZero(l)) {
+                formatter.a.append(Integer.toString(value));
+                return formatter;
+            }
+
             long v = value;
             if (value < 0
-                && (c == Conversion.OCTAL_INTEGER
+                    && (c == Conversion.OCTAL_INTEGER
                     || c == Conversion.HEXADECIMAL_INTEGER)) {
                 v += (1L << 32);
                 assert v >= 0 : v;
             }
-            print(v, l);
+            return print(formatter, v, l);
         }
 
-        private void print(long value, Locale l) throws IOException {
+        private Formatter print(Formatter formatter, long value, Locale l) throws IOException {
 
             StringBuilder sb = new StringBuilder();
 
             if (c == Conversion.DECIMAL_INTEGER) {
                 boolean neg = value < 0;
                 String valueStr = Long.toString(value, 10);
+                int pos0 = sb.length();
 
                 // leading sign indicator
                 leadingSign(sb, neg);
 
                 // the value
-                localizedMagnitude(sb, valueStr, neg ? 1 : 0, f, adjustWidth(width, f, neg), l);
+                localizedMagnitude(formatter, sb, pos0, valueStr, neg ? 1 : 0, f, adjustWidth(width, f, neg), l);
 
                 // trailing sign indicator
                 trailingSign(sb, neg);
             } else if (c == Conversion.OCTAL_INTEGER) {
                 checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE,
-                              Flags.PLUS);
+                        Flags.PLUS);
                 String s = Long.toOctalString(value);
                 int len = (f.contains(Flags.ALTERNATE)
-                           ? s.length() + 1
-                           : s.length());
+                        ? s.length() + 1
+                        : s.length());
 
                 // apply ALTERNATE (radix indicator for octal) before ZERO_PAD
                 if (f.contains(Flags.ALTERNATE))
@@ -3270,11 +3448,11 @@
                 sb.append(s);
             } else if (c == Conversion.HEXADECIMAL_INTEGER) {
                 checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE,
-                              Flags.PLUS);
+                        Flags.PLUS);
                 String s = Long.toHexString(value);
                 int len = (f.contains(Flags.ALTERNATE)
-                           ? s.length() + 2
-                           : s.length());
+                        ? s.length() + 2
+                        : s.length());
 
                 // apply ALTERNATE (radix indicator for hex) before ZERO_PAD
                 if (f.contains(Flags.ALTERNATE))
@@ -3288,11 +3466,12 @@
             }
 
             // justify based on width
-            appendJustified(a, sb);
+            appendJustified(formatter.a, sb);
+            return formatter;
         }
 
         // neg := val < 0
-        private StringBuilder leadingSign(StringBuilder sb, boolean neg) {
+        void leadingSign(StringBuilder sb, boolean neg) {
             if (!neg) {
                 if (f.contains(Flags.PLUS)) {
                     sb.append('+');
@@ -3305,27 +3484,26 @@
                 else
                     sb.append('-');
             }
-            return sb;
         }
 
         // neg := val < 0
-        private StringBuilder trailingSign(StringBuilder sb, boolean neg) {
+        void trailingSign(StringBuilder sb, boolean neg) {
             if (neg && f.contains(Flags.PARENTHESES))
                 sb.append(')');
-            return sb;
         }
 
-        private void print(BigInteger value, Locale l) throws IOException {
+        private void print(Formatter formatter, BigInteger value, Locale l) throws IOException {
             StringBuilder sb = new StringBuilder();
             boolean neg = value.signum() == -1;
             BigInteger v = value.abs();
+            int pos0 = sb.length();
 
             // leading sign indicator
             leadingSign(sb, neg);
 
             // the value
             if (c == Conversion.DECIMAL_INTEGER) {
-                localizedMagnitude(sb, v.toString(), 0, f, adjustWidth(width, f, neg), l);
+                localizedMagnitude(formatter, sb, pos0, v.toString(), 0, f, adjustWidth(width, f, neg), l);
             } else if (c == Conversion.OCTAL_INTEGER) {
                 String s = v.toString(8);
 
@@ -3366,26 +3544,27 @@
             trailingSign(sb, (value.signum() == -1));
 
             // justify based on width
-            appendJustified(a, sb);
+            appendJustified(formatter.a, sb);
         }
 
-        private void print(float value, Locale l) throws IOException {
-            print((double) value, l);
+        private Formatter print(Formatter formatter, float value, Locale l) throws IOException {
+            return print(formatter, (double) value, l);
         }
 
-        private void print(double value, Locale l) throws IOException {
-            StringBuilder sb = new StringBuilder();
+        private Formatter print(Formatter formatter, double value, Locale l) throws IOException {
+            StringBuilder sb = formatter.maybeNewStringBuilder(width);
             boolean neg = Double.compare(value, 0.0) == -1;
 
             if (!Double.isNaN(value)) {
                 double v = Math.abs(value);
+                int pos0 = sb.length();
 
                 // leading sign indicator
                 leadingSign(sb, neg);
 
                 // the value
                 if (!Double.isInfinite(v))
-                    print(sb, v, l, f, c, precision, neg);
+                    print(formatter, sb, pos0, v, l, f, c, precision, neg);
                 else
                     sb.append(f.contains(Flags.UPPERCASE)
                               ? "INFINITY" : "Infinity");
@@ -3397,11 +3576,14 @@
             }
 
             // justify based on width
-            appendJustified(a, sb);
+            if (sb != formatter.a) {
+                appendJustified(formatter.a, sb);
+            }
+            return formatter;
         }
 
         // !Double.isInfinite(value) && !Double.isNaN(value)
-        private void print(StringBuilder sb, double value, Locale l,
+        private void print(Formatter formatter, StringBuilder sb, int pos0, double value, Locale l,
                            Flags f, char c, int precision, boolean neg)
             throws IOException
         {
@@ -3430,7 +3612,7 @@
                 if (width != -1) {
                     newW = adjustWidth(width - exp.length - 1, f, neg);
                 }
-                localizedMagnitude(sb, mant, 0, f, newW, l);
+                localizedMagnitude(formatter, sb, pos0, mant, 0, f, newW, l);
 
                 sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e');
 
@@ -3438,7 +3620,7 @@
                 assert(sign == '+' || sign == '-');
                 sb.append(sign);
 
-                localizedMagnitudeExp(sb, exp, 1, l);
+                localizedMagnitudeExp(formatter, sb, exp, 1, l);
             } else if (c == Conversion.DECIMAL_FLOAT) {
                 // Create a new FormattedFloatingDecimal with the desired
                 // precision.
@@ -3459,7 +3641,7 @@
                 int newW = width;
                 if (width != -1)
                     newW = adjustWidth(width, f, neg);
-                localizedMagnitude(sb, mant, 0, f, newW, l);
+                localizedMagnitude(formatter, sb, pos0, mant, 0, f, newW, l);
             } else if (c == Conversion.GENERAL) {
                 int prec = precision;
                 if (precision == -1)
@@ -3503,7 +3685,7 @@
                     else
                         newW = adjustWidth(width, f, neg);
                 }
-                localizedMagnitude(sb, mant, 0, f, newW, l);
+                localizedMagnitude(formatter, sb, pos0, mant, 0, f, newW, l);
 
                 if (exp != null) {
                     sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e');
@@ -3512,7 +3694,7 @@
                     assert(sign == '+' || sign == '-');
                     sb.append(sign);
 
-                    localizedMagnitudeExp(sb, exp, 1, l);
+                    localizedMagnitudeExp(formatter, sb, exp, 1, l);
                 }
             } else if (c == Conversion.HEXADECIMAL_FLOAT) {
                 int prec = precision;
@@ -3561,10 +3743,7 @@
                     break;
                 }
             }
-            boolean needDot = false;
-            if (i == len) {
-                needDot = true;
-            }
+            boolean needDot = i == len;
 
             // Determine existing precision.
             int outPrec = len - i - (needDot ? 0 : 1);
@@ -3598,8 +3777,7 @@
                 // If this is subnormal input so normalize (could be faster to
                 // do as integer operation).
                 if (subnormal) {
-                    scaleUp = Math.scalb(1.0, 54);
-                    d *= scaleUp;
+                    d *= SCALEUP;
                     // Calculate the exponent.  This is not just exponent + 54
                     // since the former is not the normalized exponent.
                     exponent = Math.getExponent(d);
@@ -3665,27 +3843,28 @@
             }
         }
 
-        private void print(BigDecimal value, Locale l) throws IOException {
+        private void print(Formatter formatter, BigDecimal value, Locale l) throws IOException {
             if (c == Conversion.HEXADECIMAL_FLOAT)
                 failConversion(c, value);
             StringBuilder sb = new StringBuilder();
             boolean neg = value.signum() == -1;
             BigDecimal v = value.abs();
+            int pos0 = sb.length();
             // leading sign indicator
             leadingSign(sb, neg);
 
             // the value
-            print(sb, v, l, f, c, precision, neg);
+            print(formatter, sb, pos0, v, l, f, c, precision, neg);
 
             // trailing sign indicator
             trailingSign(sb, neg);
 
             // justify based on width
-            appendJustified(a, sb);
+            appendJustified(formatter.a, sb);
         }
 
         // value > 0
-        private void print(StringBuilder sb, BigDecimal value, Locale l,
+        private void print(Formatter formatter, StringBuilder sb, int pos0, BigDecimal value, Locale l,
                            Flags f, char c, int precision, boolean neg)
             throws IOException
         {
@@ -3733,7 +3912,7 @@
                 if (width != -1) {
                     newW = adjustWidth(width - exp.length() - 1, f, neg);
                 }
-                localizedMagnitude(sb, mant, 0, f, newW, l);
+                localizedMagnitude(formatter, sb, pos0, mant, 0, f, newW, l);
 
                 sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e');
 
@@ -3742,7 +3921,7 @@
                 assert(sign == '+' || sign == '-');
                 sb.append(sign);
 
-                sb.append(localizedMagnitude(null, exp, 1, flags, -1, l));
+                localizedMagnitude(formatter, sb, exp, 1, flags, -1, l);
             } else if (c == Conversion.DECIMAL_FLOAT) {
                 // Create a new BigDecimal with the desired precision.
                 int prec = (precision == -1 ? 6 : precision);
@@ -3783,7 +3962,7 @@
                 // number of available digits after the decimal separator.
                 trailingZeros(mant, nzeros);
 
-                localizedMagnitude(sb, mant, 0, f, adjustWidth(width, f, neg), l);
+                localizedMagnitude(formatter, sb, pos0, mant, 0, f, adjustWidth(width, f, neg), l);
             } else if (c == Conversion.GENERAL) {
                 int prec = precision;
                 if (precision == -1)
@@ -3812,10 +3991,10 @@
                     // => f precision = g precision - exponent - 1
                     prec = prec - e - 1;
 
-                    print(sb, value, l, f, Conversion.DECIMAL_FLOAT, prec,
+                    print(formatter, sb, pos0, value, l, f, Conversion.DECIMAL_FLOAT, prec,
                           neg);
                 } else {
-                    print(sb, value, l, f, Conversion.SCIENTIFIC, prec - 1, neg);
+                    print(formatter, sb, pos0, value, l, f, Conversion.SCIENTIFIC, prec - 1, neg);
                 }
             } else if (c == Conversion.HEXADECIMAL_FLOAT) {
                 // This conversion isn't supported.  The error should be
@@ -3951,19 +4130,19 @@
             }
         }
 
-        private void print(Calendar t, char c, Locale l)  throws IOException {
+        private void print(Formatter formatter, Calendar t, char c, Locale l)  throws IOException {
             StringBuilder sb = new StringBuilder();
-            print(sb, t, c, l);
+            print(formatter, sb, t, c, l);
 
             // justify based on width
             if (f.contains(Flags.UPPERCASE)) {
-                appendJustified(a, toUpperCaseWithLocale(sb.toString(), l));
+                appendJustified(formatter.a, toUpperCaseWithLocale(sb.toString(), l));
             } else {
-                appendJustified(a, sb);
+                appendJustified(formatter.a, sb);
             }
         }
 
-        private Appendable print(StringBuilder sb, Calendar t, char c, Locale l)
+        private Appendable print(Formatter formatter, StringBuilder sb, Calendar t, char c, Locale l)
                 throws IOException {
             if (sb == null)
                 sb = new StringBuilder();
@@ -3979,31 +4158,31 @@
                                || c == DateTime.HOUR_0
                                ? Flags.ZERO_PAD
                                : Flags.NONE);
-                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                localizedMagnitude(formatter, sb, i, flags, 2, l);
                 break;
             }
             case DateTime.MINUTE:      { // 'M' (00 - 59)
                 int i = t.get(Calendar.MINUTE);
                 Flags flags = Flags.ZERO_PAD;
-                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                localizedMagnitude(formatter, sb, i, flags, 2, l);
                 break;
             }
             case DateTime.NANOSECOND:  { // 'N' (000000000 - 999999999)
                 int i = t.get(Calendar.MILLISECOND) * 1000000;
                 Flags flags = Flags.ZERO_PAD;
-                sb.append(localizedMagnitude(null, i, flags, 9, l));
+                localizedMagnitude(formatter, sb, i, flags, 9, l);
                 break;
             }
             case DateTime.MILLISECOND: { // 'L' (000 - 999)
                 int i = t.get(Calendar.MILLISECOND);
                 Flags flags = Flags.ZERO_PAD;
-                sb.append(localizedMagnitude(null, i, flags, 3, l));
+                localizedMagnitude(formatter, sb, i, flags, 3, l);
                 break;
             }
             case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?)
                 long i = t.getTimeInMillis();
                 Flags flags = Flags.NONE;
-                sb.append(localizedMagnitude(null, i, flags, width, l));
+                localizedMagnitude(formatter, sb, i, flags, width, l);
                 break;
             }
             case DateTime.AM_PM:       { // 'p' (am or pm)
@@ -4021,13 +4200,13 @@
             case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
                 long i = t.getTimeInMillis() / 1000;
                 Flags flags = Flags.NONE;
-                sb.append(localizedMagnitude(null, i, flags, width, l));
+                localizedMagnitude(formatter, sb, i, flags, width, l);
                 break;
             }
             case DateTime.SECOND:      { // 'S' (00 - 60 - leap second)
                 int i = t.get(Calendar.SECOND);
                 Flags flags = Flags.ZERO_PAD;
-                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                localizedMagnitude(formatter, sb, i, flags, 2, l);
                 break;
             }
             case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus?
@@ -4041,7 +4220,7 @@
                 int offset = (min / 60) * 100 + (min % 60);
                 Flags flags = Flags.ZERO_PAD;
 
-                sb.append(localizedMagnitude(null, offset, flags, 4, l));
+                localizedMagnitude(formatter, sb, offset, flags, 4, l);
                 break;
             }
             case DateTime.ZONE:        { // 'Z' (symbol)
@@ -4093,7 +4272,7 @@
                     break;
                 }
                 Flags flags = Flags.ZERO_PAD;
-                sb.append(localizedMagnitude(null, i, flags, size, l));
+                localizedMagnitude(formatter, sb, i, flags, size, l);
                 break;
             }
             case DateTime.DAY_OF_MONTH_0:         // 'd' (01 - 31)
@@ -4102,19 +4281,19 @@
                 Flags flags = (c == DateTime.DAY_OF_MONTH_0
                                ? Flags.ZERO_PAD
                                : Flags.NONE);
-                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                localizedMagnitude(formatter, sb, i, flags, 2, l);
                 break;
             }
             case DateTime.DAY_OF_YEAR:          { // 'j' (001 - 366)
                 int i = t.get(Calendar.DAY_OF_YEAR);
                 Flags flags = Flags.ZERO_PAD;
-                sb.append(localizedMagnitude(null, i, flags, 3, l));
+                localizedMagnitude(formatter, sb, i, flags, 3, l);
                 break;
             }
             case DateTime.MONTH:                { // 'm' (01 - 12)
                 int i = t.get(Calendar.MONTH) + 1;
                 Flags flags = Flags.ZERO_PAD;
-                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                localizedMagnitude(formatter, sb, i, flags, 2, l);
                 break;
             }
 
@@ -4122,48 +4301,48 @@
             case DateTime.TIME:         // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS)
             case DateTime.TIME_24_HOUR:    { // 'R' (hh:mm same as %H:%M)
                 char sep = ':';
-                print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
-                print(sb, t, DateTime.MINUTE, l);
+                print(formatter, sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
+                print(formatter, sb, t, DateTime.MINUTE, l);
                 if (c == DateTime.TIME) {
                     sb.append(sep);
-                    print(sb, t, DateTime.SECOND, l);
+                    print(formatter, sb, t, DateTime.SECOND, l);
                 }
                 break;
             }
             case DateTime.TIME_12_HOUR:    { // 'r' (hh:mm:ss [AP]M)
                 char sep = ':';
-                print(sb, t, DateTime.HOUR_0, l).append(sep);
-                print(sb, t, DateTime.MINUTE, l).append(sep);
-                print(sb, t, DateTime.SECOND, l).append(' ');
+                print(formatter, sb, t, DateTime.HOUR_0, l).append(sep);
+                print(formatter, sb, t, DateTime.MINUTE, l).append(sep);
+                print(formatter, sb, t, DateTime.SECOND, l).append(' ');
                 // this may be in wrong place for some locales
                 StringBuilder tsb = new StringBuilder();
-                print(tsb, t, DateTime.AM_PM, l);
+                print(formatter, tsb, t, DateTime.AM_PM, l);
 
                 sb.append(toUpperCaseWithLocale(tsb.toString(), l));
                 break;
             }
             case DateTime.DATE_TIME:    { // 'c' (Sat Nov 04 12:02:33 EST 1999)
                 char sep = ' ';
-                print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
-                print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
-                print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
-                print(sb, t, DateTime.TIME, l).append(sep);
-                print(sb, t, DateTime.ZONE, l).append(sep);
-                print(sb, t, DateTime.YEAR_4, l);
+                print(formatter, sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
+                print(formatter, sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
+                print(formatter, sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                print(formatter, sb, t, DateTime.TIME, l).append(sep);
+                print(formatter, sb, t, DateTime.ZONE, l).append(sep);
+                print(formatter, sb, t, DateTime.YEAR_4, l);
                 break;
             }
             case DateTime.DATE:            { // 'D' (mm/dd/yy)
                 char sep = '/';
-                print(sb, t, DateTime.MONTH, l).append(sep);
-                print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
-                print(sb, t, DateTime.YEAR_2, l);
+                print(formatter, sb, t, DateTime.MONTH, l).append(sep);
+                print(formatter, sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                print(formatter, sb, t, DateTime.YEAR_2, l);
                 break;
             }
             case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
                 char sep = '-';
-                print(sb, t, DateTime.YEAR_4, l).append(sep);
-                print(sb, t, DateTime.MONTH, l).append(sep);
-                print(sb, t, DateTime.DAY_OF_MONTH_0, l);
+                print(formatter, sb, t, DateTime.YEAR_4, l).append(sep);
+                print(formatter, sb, t, DateTime.MONTH, l).append(sep);
+                print(formatter, sb, t, DateTime.DAY_OF_MONTH_0, l);
                 break;
             }
             default:
@@ -4172,18 +4351,18 @@
             return sb;
         }
 
-        private void print(TemporalAccessor t, char c, Locale l)  throws IOException {
+        private void print(Formatter formatter, TemporalAccessor t, char c, Locale l)  throws IOException {
             StringBuilder sb = new StringBuilder();
-            print(sb, t, c, l);
+            print(formatter, sb, t, c, l);
             // justify based on width
             if (f.contains(Flags.UPPERCASE)) {
-                appendJustified(a, toUpperCaseWithLocale(sb.toString(), l));
+                appendJustified(formatter.a, toUpperCaseWithLocale(sb.toString(), l));
             } else {
-                appendJustified(a, sb);
+                appendJustified(formatter.a, sb);
             }
         }
 
-        private Appendable print(StringBuilder sb, TemporalAccessor t, char c,
+        private Appendable print(Formatter formatter, StringBuilder sb, TemporalAccessor t, char c,
                                  Locale l) throws IOException {
             if (sb == null)
                 sb = new StringBuilder();
@@ -4191,28 +4370,28 @@
                 switch (c) {
                 case DateTime.HOUR_OF_DAY_0: {  // 'H' (00 - 23)
                     int i = t.get(ChronoField.HOUR_OF_DAY);
-                    sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
+                    localizedMagnitude(formatter, sb, i, Flags.ZERO_PAD, 2, l);
                     break;
                 }
                 case DateTime.HOUR_OF_DAY: {   // 'k' (0 - 23) -- like H
                     int i = t.get(ChronoField.HOUR_OF_DAY);
-                    sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
+                    localizedMagnitude(formatter, sb, i, Flags.NONE, 2, l);
                     break;
                 }
                 case DateTime.HOUR_0:      {  // 'I' (01 - 12)
                     int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
-                    sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
+                    localizedMagnitude(formatter, sb, i, Flags.ZERO_PAD, 2, l);
                     break;
                 }
                 case DateTime.HOUR:        { // 'l' (1 - 12) -- like I
                     int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
-                    sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
+                    localizedMagnitude(formatter, sb, i, Flags.NONE, 2, l);
                     break;
                 }
                 case DateTime.MINUTE:      { // 'M' (00 - 59)
                     int i = t.get(ChronoField.MINUTE_OF_HOUR);
                     Flags flags = Flags.ZERO_PAD;
-                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    localizedMagnitude(formatter, sb, i, flags, 2, l);
                     break;
                 }
                 case DateTime.NANOSECOND:  { // 'N' (000000000 - 999999999)
@@ -4223,20 +4402,20 @@
                         i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000;
                     }
                     Flags flags = Flags.ZERO_PAD;
-                    sb.append(localizedMagnitude(null, i, flags, 9, l));
+                    localizedMagnitude(formatter, sb, i, flags, 9, l);
                     break;
                 }
                 case DateTime.MILLISECOND: { // 'L' (000 - 999)
                     int i = t.get(ChronoField.MILLI_OF_SECOND);
                     Flags flags = Flags.ZERO_PAD;
-                    sb.append(localizedMagnitude(null, i, flags, 3, l));
+                    localizedMagnitude(formatter, sb, i, flags, 3, l);
                     break;
                 }
                 case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?)
                     long i = t.getLong(ChronoField.INSTANT_SECONDS) * 1000L +
                              t.getLong(ChronoField.MILLI_OF_SECOND);
                     Flags flags = Flags.NONE;
-                    sb.append(localizedMagnitude(null, i, flags, width, l));
+                    localizedMagnitude(formatter, sb, i, flags, width, l);
                     break;
                 }
                 case DateTime.AM_PM:       { // 'p' (am or pm)
@@ -4254,13 +4433,13 @@
                 case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
                     long i = t.getLong(ChronoField.INSTANT_SECONDS);
                     Flags flags = Flags.NONE;
-                    sb.append(localizedMagnitude(null, i, flags, width, l));
+                    localizedMagnitude(formatter, sb, i, flags, width, l);
                     break;
                 }
                 case DateTime.SECOND:      { // 'S' (00 - 60 - leap second)
                     int i = t.get(ChronoField.SECOND_OF_MINUTE);
                     Flags flags = Flags.ZERO_PAD;
-                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    localizedMagnitude(formatter, sb, i, flags, 2, l);
                     break;
                 }
                 case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus?
@@ -4273,7 +4452,7 @@
                     // combine minute and hour into a single integer
                     int offset = (min / 60) * 100 + (min % 60);
                     Flags flags = Flags.ZERO_PAD;
-                    sb.append(localizedMagnitude(null, offset, flags, 4, l));
+                    localizedMagnitude(formatter, sb, offset, flags, 4, l);
                     break;
                 }
                 case DateTime.ZONE:        { // 'Z' (symbol)
@@ -4334,7 +4513,7 @@
                         break;
                     }
                     Flags flags = Flags.ZERO_PAD;
-                    sb.append(localizedMagnitude(null, i, flags, size, l));
+                    localizedMagnitude(formatter, sb, i, flags, size, l);
                     break;
                 }
                 case DateTime.DAY_OF_MONTH_0:         // 'd' (01 - 31)
@@ -4343,19 +4522,19 @@
                     Flags flags = (c == DateTime.DAY_OF_MONTH_0
                                    ? Flags.ZERO_PAD
                                    : Flags.NONE);
-                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    localizedMagnitude(formatter, sb, i, flags, 2, l);
                     break;
                 }
                 case DateTime.DAY_OF_YEAR:          { // 'j' (001 - 366)
                     int i = t.get(ChronoField.DAY_OF_YEAR);
                     Flags flags = Flags.ZERO_PAD;
-                    sb.append(localizedMagnitude(null, i, flags, 3, l));
+                    localizedMagnitude(formatter, sb, i, flags, 3, l);
                     break;
                 }
                 case DateTime.MONTH:                { // 'm' (01 - 12)
                     int i = t.get(ChronoField.MONTH_OF_YEAR);
                     Flags flags = Flags.ZERO_PAD;
-                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    localizedMagnitude(formatter, sb, i, flags, 2, l);
                     break;
                 }
 
@@ -4363,47 +4542,47 @@
                 case DateTime.TIME:         // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS)
                 case DateTime.TIME_24_HOUR:    { // 'R' (hh:mm same as %H:%M)
                     char sep = ':';
-                    print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
-                    print(sb, t, DateTime.MINUTE, l);
+                    print(formatter, sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
+                    print(formatter, sb, t, DateTime.MINUTE, l);
                     if (c == DateTime.TIME) {
                         sb.append(sep);
-                        print(sb, t, DateTime.SECOND, l);
+                        print(formatter, sb, t, DateTime.SECOND, l);
                     }
                     break;
                 }
                 case DateTime.TIME_12_HOUR:    { // 'r' (hh:mm:ss [AP]M)
                     char sep = ':';
-                    print(sb, t, DateTime.HOUR_0, l).append(sep);
-                    print(sb, t, DateTime.MINUTE, l).append(sep);
-                    print(sb, t, DateTime.SECOND, l).append(' ');
+                    print(formatter, sb, t, DateTime.HOUR_0, l).append(sep);
+                    print(formatter, sb, t, DateTime.MINUTE, l).append(sep);
+                    print(formatter, sb, t, DateTime.SECOND, l).append(' ');
                     // this may be in wrong place for some locales
                     StringBuilder tsb = new StringBuilder();
-                    print(tsb, t, DateTime.AM_PM, l);
+                    print(formatter, tsb, t, DateTime.AM_PM, l);
                     sb.append(toUpperCaseWithLocale(tsb.toString(), l));
                     break;
                 }
                 case DateTime.DATE_TIME:    { // 'c' (Sat Nov 04 12:02:33 EST 1999)
                     char sep = ' ';
-                    print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
-                    print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
-                    print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
-                    print(sb, t, DateTime.TIME, l).append(sep);
-                    print(sb, t, DateTime.ZONE, l).append(sep);
-                    print(sb, t, DateTime.YEAR_4, l);
+                    print(formatter, sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
+                    print(formatter, sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
+                    print(formatter, sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                    print(formatter, sb, t, DateTime.TIME, l).append(sep);
+                    print(formatter, sb, t, DateTime.ZONE, l).append(sep);
+                    print(formatter, sb, t, DateTime.YEAR_4, l);
                     break;
                 }
                 case DateTime.DATE:            { // 'D' (mm/dd/yy)
                     char sep = '/';
-                    print(sb, t, DateTime.MONTH, l).append(sep);
-                    print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
-                    print(sb, t, DateTime.YEAR_2, l);
+                    print(formatter, sb, t, DateTime.MONTH, l).append(sep);
+                    print(formatter, sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                    print(formatter, sb, t, DateTime.YEAR_2, l);
                     break;
                 }
                 case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
                     char sep = '-';
-                    print(sb, t, DateTime.YEAR_4, l).append(sep);
-                    print(sb, t, DateTime.MONTH, l).append(sep);
-                    print(sb, t, DateTime.DAY_OF_MONTH_0, l);
+                    print(formatter, sb, t, DateTime.YEAR_4, l).append(sep);
+                    print(formatter, sb, t, DateTime.MONTH, l).append(sep);
+                    print(formatter, sb, t, DateTime.DAY_OF_MONTH_0, l);
                     break;
                 }
                 default:
@@ -4422,32 +4601,36 @@
             throw new FormatFlagsConversionMismatchException(fs, c);
         }
 
-        private void failConversion(char c, Object arg) {
+        void failConversion(char c, Object arg) {
             throw new IllegalFormatConversionException(c, arg.getClass());
         }
 
-        private char getZero(Locale l) {
-            if ((l != null) &&  !l.equals(locale())) {
+        private char getZero(Formatter formatter, Locale l) {
+            if ((l != null) &&  !l.equals(formatter.locale())) {
                 DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
                 return dfs.getZeroDigit();
             }
-            return zero;
+            return formatter.zero;
         }
 
-        private StringBuilder localizedMagnitude(StringBuilder sb,
+        private StringBuilder localizedMagnitude(Formatter formatter, StringBuilder sb,
                 long value, Flags f, int width, Locale l) {
-            return localizedMagnitude(sb, Long.toString(value, 10), 0, f, width, l);
+            return localizedMagnitude(formatter, sb, Long.toString(value, 10), 0, f, width, l);
         }
 
-        private StringBuilder localizedMagnitude(StringBuilder sb,
-                CharSequence value, final int offset, Flags f, int width,
-                Locale l) {
+        StringBuilder localizedMagnitude(Formatter formatter, StringBuilder sb,
+                                         CharSequence value, final int offset, Flags f, int width, Locale l) {
+            return localizedMagnitude(formatter, sb, sb == null ? 0 : sb.length(), value, offset, f, width, l);
+        }
+
+        StringBuilder localizedMagnitude(Formatter formatter, StringBuilder sb, int pos0,
+                                         CharSequence value, final int offset, Flags f, int width, Locale l) {
             if (sb == null) {
                 sb = new StringBuilder();
             }
             int begin = sb.length();
 
-            char zero = getZero(l);
+            char zero = getZero(formatter, l);
 
             // determine localized grouping separator and size
             char grpSep = '\0';
@@ -4527,7 +4710,7 @@
 
             // apply zero padding
             if (width != -1 && f.contains(Flags.ZERO_PAD)) {
-                for (int k = sb.length(); k < width; k++) {
+                for (int k = sb.length() - pos0; k < width; k++) {
                     sb.insert(begin, zero);
                 }
             }
@@ -4538,9 +4721,9 @@
         // Specialized localization of exponents, where the source value can only
         // contain characters '0' through '9', starting at index offset, and no
         // group separators is added for any locale.
-        private void localizedMagnitudeExp(StringBuilder sb, char[] value,
+        private void localizedMagnitudeExp(Formatter formatter, StringBuilder sb, char[] value,
                 final int offset, Locale l) {
-            char zero = getZero(l);
+            char zero = getZero(formatter, l);
 
             int len = value.length;
             for (int j = offset; j < len; j++) {
@@ -4582,6 +4765,10 @@
             return (flags & f.valueOf()) == f.valueOf();
         }
 
+        public boolean isEmpty() {
+            return flags == 0;
+        }
+
         public Flags dup() {
             return new Flags(flags);
         }
--- a/src/java.base/share/classes/java/util/Objects.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/src/java.base/share/classes/java/util/Objects.java	Wed Oct 31 11:08:50 2018 -0300
@@ -28,6 +28,7 @@
 import jdk.internal.util.Preconditions;
 import jdk.internal.vm.annotation.ForceInline;
 
+import java.lang.compiler.IntrinsicCandidate;
 import java.util.function.Supplier;
 
 /**
@@ -142,6 +143,7 @@
     * @see Arrays#hashCode(Object[])
     * @see List#hashCode
     */
+    @IntrinsicCandidate
     public static int hash(Object... values) {
         return Arrays.hashCode(values);
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Wed Oct 31 11:08:50 2018 -0300
@@ -215,7 +215,8 @@
     public final Type functionalInterfaceType;
     public final Type constableType;
     public final Type constantDescType;
-
+    public final Type intrinsicCandidateType;
+    public final Type programType;
     /** The symbol representing the length field of an array.
      */
     public final VarSymbol lengthVar;
@@ -571,6 +572,9 @@
         functionalInterfaceType = enterClass("java.lang.FunctionalInterface");
         constableType = enterClass("java.lang.constant.Constable");
         constantDescType = enterClass("java.lang.constant.ConstantDesc");
+        intrinsicCandidateType =
+                enterClass("java.lang.compiler.IntrinsicCandidate");
+        programType = enterClass("java.lang.Program");
 
         synthesizeEmptyInterfaceIfMissing(autoCloseableType);
         synthesizeEmptyInterfaceIfMissing(cloneableType);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/IntrinsicsVisitor.java	Wed Oct 31 11:08:50 2018 -0300
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+package com.sun.tools.javac.comp;
+
+import com.sun.tools.javac.code.Attribute.Compound;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol;
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Type.MethodType;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.intrinsics.IntrinsicContext;
+import com.sun.tools.javac.intrinsics.IntrinsicProcessor;
+import com.sun.tools.javac.intrinsics.IntrinsicProcessorFactory;
+import com.sun.tools.javac.intrinsics.Intrinsics;
+import com.sun.tools.javac.intrinsics.IntrinsicProcessor.Result;
+import com.sun.tools.javac.jvm.ClassFile;
+import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.resources.CompilerProperties.Warnings;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.TreeTranslator;
+import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Names;
+import com.sun.tools.javac.util.Options;
+
+import java.lang.constant.ClassDesc;
+import java.lang.constant.ConstantDesc;
+import java.lang.constant.ConstantDescs;
+import java.lang.constant.DirectMethodHandleDesc;
+import java.lang.constant.DirectMethodHandleDesc.Kind;
+import java.lang.constant.DynamicCallSiteDesc;
+import java.lang.constant.MethodHandleDesc;
+import java.lang.constant.MethodTypeDesc;
+
+import java.lang.invoke.MethodHandles;
+
+import static com.sun.tools.javac.code.Flags.STATIC;
+import static com.sun.tools.javac.code.TypeTag.BOT;
+
+/**
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class IntrinsicsVisitor {
+    protected static final Context.Key<IntrinsicsVisitor> intrinsicsVisitorKey = new Context.Key<>();
+
+    private boolean disableIntrinsics;
+
+    private final Names names;
+    private final Symtab syms;
+    private final Resolve rs;
+    private final Types types;
+    private TransTypes transTypes;
+    private final Log log;
+    private final TreeMaker make;
+    private final MethodHandles.Lookup lookup;
+    private ClassSymbol outerMostClass;
+    private ClassSymbol thisClass;
+    private MethodSymbol thisMethod;
+
+    private Env<AttrContext> attrEnv;
+    private DiagnosticPosition nopos;
+
+    public static IntrinsicsVisitor instance(Context context) {
+        IntrinsicsVisitor instance = context.get(intrinsicsVisitorKey);
+
+        if (instance == null)
+            instance = new IntrinsicsVisitor(context);
+        return instance;
+    }
+
+    IntrinsicsVisitor(Context context) {
+        context.put(intrinsicsVisitorKey, this);
+        Options options = Options.instance(context);
+        disableIntrinsics = options.isSet("disableIntrinsics");
+        names = Names.instance(context);
+        syms = Symtab.instance(context);
+        rs = Resolve.instance(context);
+        types = Types.instance(context);
+        transTypes = TransTypes.instance(context);
+        log = Log.instance(context);
+        make = TreeMaker.instance(context);
+        lookup = MethodHandles.lookup();
+     }
+
+    public JCTree analyzeTree(JCTree tree, Env<AttrContext> attrEnv) {
+        if (disableIntrinsics ||
+                !(tree instanceof JCTree.JCClassDecl) ||
+                tree.type.tsym.packge().modle == syms.java_base) {
+            return tree;
+        }
+
+        this.attrEnv = attrEnv;
+        this.outerMostClass = ((JCClassDecl)tree).sym;
+
+        return translator.translate(tree);
+    }
+
+    private static ConstantDesc<?> typeConstantDesc(Type type) {
+        if (type.getTag() == BOT) {
+            return ConstantDescs.NULL;
+        }
+
+        Object constant = type.constValue();
+
+        if (constant == null) {
+            return null;
+        }
+
+        return constant instanceof ConstantDesc ? (ConstantDesc<?>)constant : null;
+    }
+
+    private Object resolveConstantDesc(ConstantDesc<?> constantDesc) {
+        try {
+            return constantDesc.resolveConstantDesc(lookup);
+        } catch (ReflectiveOperationException ex) {
+            // Fall thru
+        }
+        return null;
+    }
+
+    private ClassDesc typeClassDesc(Type type) {
+        return ClassDesc.ofDescriptor(signature(types.erasure(type)));
+    }
+
+    private MethodTypeDesc methodTypeDesc(Type type) {
+        return MethodTypeDesc.ofDescriptor(signature(types.erasure(type)));
+    }
+
+    private Name fullName(ClassDesc cd) {
+        if (cd.packageName().isEmpty()) {
+            return names.fromString(cd.displayName());
+        }
+
+        return names.fromString(cd.packageName() + "." + cd.displayName());
+    }
+
+    class TransformIntrinsic {
+        private final MethodSymbol msym;
+
+        TransformIntrinsic(MethodSymbol msym) {
+            this.msym = msym;
+        }
+
+        public JCTree translate(JCMethodInvocation tree) {
+            if (!(tree.meth instanceof JCFieldAccess)) {
+                return tree;
+            }
+
+            JCFieldAccess meth = (JCFieldAccess)tree.meth;
+            ClassDesc owner = ClassDesc.of(meth.sym.owner.toString());
+            String methodName = msym.name.toString();
+            MethodTypeDesc methodTypeDesc = methodTypeDesc(msym.type);
+            boolean isStatic = (msym.flags() & STATIC) != 0;
+            List<JCExpression>args = tree.args;
+            int argSize = args.size();
+            int offset = isStatic ? 0 : 1;
+
+            int allArgsSize = offset + argSize;
+            JCExpression[] allArgs = new JCExpression[allArgsSize];
+            ClassDesc[] argClassDescs = new ClassDesc[allArgsSize];
+            ConstantDesc<?>[] constantArgs = new ConstantDesc<?>[allArgsSize];
+
+            if (!isStatic) {
+                JCExpression selected = meth.selected;
+                allArgs[0] = selected;
+                argClassDescs[0] = typeClassDesc(selected.type);
+                constantArgs[0] = typeConstantDesc(selected.type);
+            }
+
+            for (int i = 0; i < argSize; i++) {
+                JCExpression arg = args.get(i);
+
+                if (arg == null) {
+                    return tree;
+                }
+
+                int io = i + offset;
+                allArgs[io] = arg;
+                argClassDescs[io] = typeClassDesc(arg.type);
+                constantArgs[io] = typeConstantDesc(arg.type);
+            }
+
+            IntrinsicProcessorFactory factory = Intrinsics.getProcessorFactory(
+                    owner,
+                    methodName,
+                    methodTypeDesc
+            );
+
+            if (factory == null) {
+                return tree;
+            }
+
+            IntrinsicsVisitorContext intrinsicContext = new IntrinsicsVisitorContext(tree, allArgs);
+            IntrinsicProcessor processor = factory.processor();
+            Result result = processor.tryIntrinsify(
+                    intrinsicContext,
+                    owner,
+                    methodName,
+                    methodTypeDesc,
+                    isStatic,
+                    argClassDescs,
+                    constantArgs
+            );
+
+            if (result instanceof Result.None) {
+                return tree;
+            } else if (result instanceof Result.Ldc) {
+                Result.Ldc ldc = (Result.Ldc)result;
+                Object constant = ldc.constant();
+                JCExpression value;
+
+                if (constant == null) {
+                    value = make.Literal(BOT, null).setType(syms.botType);
+                } else if (constant instanceof ClassDesc) {
+                    ClassDesc classDesc = (ClassDesc)constant;
+                    Name fullName = fullName(classDesc);
+                    ClassSymbol classSym = syms.enterClass(attrEnv.toplevel.modle, fullName);
+                    value = make.ClassLiteral(classSym);
+                } else {
+                    value = make.Literal(constant);
+                }
+
+                return transTypes.coerce(attrEnv,  value, meth.type.getReturnType());
+            } else if (result instanceof Result.Indy) {
+                Result.Indy indy = (Result.Indy)result;
+                DynamicCallSiteDesc callSite = indy.indy();
+                String invocationName = callSite.invocationName();
+                DirectMethodHandleDesc bootstrapMethod = (DirectMethodHandleDesc)callSite.bootstrapMethod();
+                ClassDesc ownerClass = bootstrapMethod.owner();
+                String bootstrapName = bootstrapMethod.methodName();
+                List<Object> staticArgs = List.nil();
+
+                for (ConstantDesc<?> constantDesc : callSite.bootstrapArgs()) {
+                    staticArgs = staticArgs.append(resolveConstantDesc(constantDesc));
+                }
+
+                List<JCExpression> indyArgs = List.nil();
+                for (int i : indy.args()) {
+                    indyArgs = indyArgs.append(allArgs[i]);
+                }
+
+                List<Type> argTypes = List.nil();
+                for (JCExpression arg : indyArgs) {
+                    if (arg.type == syms.botType) {
+                        argTypes = argTypes.append(syms.objectType);
+                    } else {
+                        argTypes = argTypes.append(arg.type);
+                    }
+                }
+
+                Type returnType = msym.type.getReturnType();
+                MethodType indyType = new MethodType(argTypes, returnType,  List.nil(), syms.methodClass);
+                ClassSymbol classSymbol = syms.enterClass(msym.packge().modle, fullName(ownerClass));
+
+                return makeDynamicCall(
+                        new SimpleDiagnosticPosition(tree.pos),
+                        classSymbol.type,
+                        names.fromString(bootstrapName),
+                        staticArgs,
+                        indyType,
+                        indyArgs,
+                        names.fromString(invocationName)
+                );
+            } else {
+                assert false : "tryIntrinsifyMethod result unknown";
+            }
+
+            return tree;
+        }
+    }
+
+    Translator translator = new Translator();
+    class Translator extends TreeTranslator {
+        @Override
+        public void visitApply(JCMethodInvocation tree) {
+            super.visitApply(tree);
+            Name methName = TreeInfo.name(tree.meth);
+
+            if (methName == names._this || methName == names._super) {
+                return;
+            }
+
+            MethodSymbol msym = (MethodSymbol)TreeInfo.symbol(tree.meth);
+            Compound attr = msym.attribute(syms.intrinsicCandidateType.tsym);
+
+            if (attr != null) {
+                TransformIntrinsic transform = new TransformIntrinsic(msym);
+                result = transform.translate(tree);
+            }
+        }
+
+        @Override
+        public void visitClassDef(JCClassDecl tree) {
+            ClassSymbol saveClass = thisClass;
+            thisClass = tree.sym;
+            super.visitClassDef(tree);
+            thisClass = saveClass;
+        }
+
+        @Override
+        public void visitMethodDef(JCMethodDecl tree) {
+            MethodSymbol saveMethod = thisMethod;
+            thisMethod = tree.sym;
+            super.visitMethodDef(tree);
+            thisMethod = saveMethod;
+        }
+    }
+
+    private JCExpression makeDynamicCall(DiagnosticPosition pos, Type site, Name bsmName,
+                                         List<Object> staticArgs, MethodType indyType,
+                                         List<JCExpression> indyArgs,
+                                         Name methName) {
+        int prevPos = make.pos;
+        try {
+            make.at(pos);
+            List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+                    syms.stringType,
+                    syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs));
+            Symbol bsm = rs.resolveQualifiedMethod(pos, attrEnv, site,
+                    bsmName, bsm_staticArgs, List.nil());
+            DynamicMethodSymbol dynSym =
+                    new DynamicMethodSymbol(methName,
+                            syms.noSymbol,
+                            ClassFile.REF_invokeStatic,
+                            (MethodSymbol)bsm,
+                            indyType,
+                            staticArgs.toArray());
+
+            JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName);
+            qualifier.sym = dynSym;
+            qualifier.type = indyType;
+            JCMethodInvocation proxyCall = make.Apply(List.nil(), qualifier, indyArgs);
+            proxyCall.type = indyType.getReturnType();
+
+            return proxyCall;
+        } finally {
+            make.at(prevPos);
+        }
+    }
+
+    private List<Type> bsmStaticArgToTypes(List<Object> args) {
+        ListBuffer<Type> argtypes = new ListBuffer<>();
+
+        for (Object arg : args) {
+            argtypes.append(bsmStaticArgToType(arg));
+        }
+
+        return argtypes.toList();
+    }
+
+    private Type bsmStaticArgToType(Object arg) {
+        if (arg == null) {
+            return syms.objectType;
+        } else if (arg instanceof ClassSymbol) {
+            return syms.classType;
+        } else if (arg instanceof Integer) {
+            return syms.intType;
+        } else if (arg instanceof Long) {
+            return syms.longType;
+        } else if (arg instanceof Float) {
+            return syms.floatType;
+        } else if (arg instanceof Double) {
+            return syms.doubleType;
+        } else if (arg instanceof String) {
+            return syms.stringType;
+        } else {
+            Assert.error("bad static arg " + arg);
+            return null;
+        }
+    }
+
+    private String signature(Type type) {
+        SignatureGenerator generator = new SignatureGenerator();
+        generator.assembleSig(type.getTag() == BOT ? syms.objectType : type);
+
+        return generator.toString();
+    }
+
+    private class SignatureGenerator extends Types.SignatureGenerator {
+        StringBuilder sb = new StringBuilder();
+
+        SignatureGenerator() {
+            super(types);
+        }
+
+        @Override
+        protected void append(char ch) {
+            sb.append(ch);
+        }
+
+        @Override
+        protected void append(byte[] ba) {
+            sb.append(new String(ba));
+        }
+
+        @Override
+        protected void append(Name name) {
+            sb.append(name.toString());
+        }
+
+        @Override
+        public String toString() {
+            return sb.toString();
+        }
+    }
+
+    private class IntrinsicsVisitorContext implements IntrinsicContext {
+        private JCMethodInvocation tree;
+        private JCExpression[] allArgs;
+
+        IntrinsicsVisitorContext(JCMethodInvocation tree, JCExpression[] allArgs) {
+            this.tree = tree;
+            this.allArgs = allArgs;
+        }
+
+        @Override
+        public void warning(String message) {
+            log.warning(new SimpleDiagnosticPosition(tree.pos),
+                    Warnings.IntrinsicWarning(message));
+        }
+
+        @Override
+        public void warning(String message, int arg) {
+            assert 0 < arg && arg < allArgs.length : "arg index out of range";
+            log.warning(new SimpleDiagnosticPosition(allArgs[arg].pos),
+                    Warnings.IntrinsicWarning(message));
+        }
+
+        @Override
+        public void warning(String message, int arg, int offset) {
+            assert 0 < arg && arg < allArgs.length : "arg index out of range";
+            log.warning(new SimpleDiagnosticPosition(allArgs[arg].pos + offset),
+                    Warnings.IntrinsicWarning(message));
+        }
+
+        @Override
+        public void error(String message) {
+            log.error(new SimpleDiagnosticPosition(tree.pos),
+                    Errors.IntrinsicError(message));
+        }
+
+        @Override
+        public void error(String message, int arg) {
+            assert 0 < arg && arg < allArgs.length : "arg index out of range";
+            log.error(new SimpleDiagnosticPosition(allArgs[arg].pos),
+                    Errors.IntrinsicError(message));
+        }
+
+        @Override
+        public void error(String message, int arg, int offset) {
+            assert 0 < arg && arg < allArgs.length : "arg index out of range";
+            log.error(new SimpleDiagnosticPosition(allArgs[arg].pos + offset),
+                    Errors.IntrinsicError(message));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/FormatterProcessorFactory.java	Wed Oct 31 11:08:50 2018 -0300
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+package com.sun.tools.javac.intrinsics;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.lang.constant.ClassDesc;
+import java.lang.constant.ConstantDesc;
+import java.lang.constant.ConstantDescs;
+import java.lang.constant.DynamicCallSiteDesc;
+import java.lang.constant.MethodTypeDesc;
+import java.util.Locale;
+
+/**
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class FormatterProcessorFactory implements IntrinsicProcessorFactory {
+    @Override
+    public void register() {
+        // static String methods
+        Intrinsics.register(this,
+                String.class, "format", String.class, String.class, Object[].class);
+        Intrinsics.register(this,
+                String.class, "format", String.class, Locale.class, String.class, Object[].class);
+
+        // instance String methods
+        Intrinsics.register(this,
+                String.class, "format", String.class, Object[].class);
+        Intrinsics.register(this,
+                String.class, "format", String.class, Locale.class, Object[].class);
+
+        // others
+        Intrinsics.register(this,
+                PrintStream.class, "printf", PrintStream.class, String.class, Object[].class);
+        Intrinsics.register(this,
+                PrintStream.class, "printf", PrintStream.class, Locale.class, String.class, Object[].class);
+        Intrinsics.register(this,
+                PrintStream.class, "format", PrintStream.class, String.class, Object[].class);
+        Intrinsics.register(this,
+                PrintStream.class, "format", PrintStream.class, Locale.class, String.class, Object[].class);
+        Intrinsics.register(this,
+                PrintWriter.class, "printf", PrintWriter.class, String.class, Object[].class);
+        Intrinsics.register(this,
+                PrintWriter.class, "printf", PrintWriter.class, Locale.class, String.class, Object[].class);
+        Intrinsics.register(this,
+                PrintWriter.class, "format", PrintWriter.class, String.class, Object[].class);
+        Intrinsics.register(this,
+                PrintWriter.class, "format", PrintWriter.class, Locale.class, String.class, Object[].class);
+    }
+
+    private static FormatterProcessor instance;
+
+    @Override
+    public IntrinsicProcessor processor() {
+        if (instance == null) {
+            instance = new FormatterProcessor();
+        }
+
+        return instance;
+    }
+
+    static class FormatterProcessor implements IntrinsicProcessor {
+        static String lowerFirst(String string) {
+            return string.substring(0, 1).toLowerCase() + string.substring(1);
+        }
+
+        static String upperFirst(String string) {
+            return string.substring(0, 1).toUpperCase() + string.substring(1);
+        }
+
+        private String getBSMName(ClassDesc ownerDesc, String methodName, boolean isStatic, boolean hasLocale) {
+            StringBuffer sb = new StringBuffer(32);
+
+            if (isStatic) {
+                sb.append("static");
+                sb.append(ownerDesc.displayName());
+            } else {
+                sb.append(lowerFirst(ownerDesc.displayName()));
+            }
+
+            if (hasLocale) {
+                sb.append("Locale");
+            }
+
+            sb.append(upperFirst(methodName));
+            sb.append("Bootstrap");
+
+            return sb.toString();
+        }
+
+        @Override
+        public Result tryIntrinsify(IntrinsicContext intrinsicContext,
+                                    ClassDesc ownerDesc,
+                                    String methodName,
+                                    MethodTypeDesc methodType,
+                                    boolean isStatic,
+                                    ClassDesc[] argClassDescs,
+                                    ConstantDesc<?>[] constantArgs) {
+            // Don't bother in array vararg case.
+            if (Intrinsics.isArrayVarArg(argClassDescs, methodType.parameterCount())) {
+                return new Result.None();
+            }
+
+            boolean hasLocale;
+            int formatArg;
+
+            if (!ClassDesc.of("java.lang.String").equals(ownerDesc)) {
+                hasLocale = ClassDesc.of("java.util.Locale").equals(methodType.parameterType(1));
+                formatArg = hasLocale ? 2 : 1;
+            } else  if (isStatic) {
+                hasLocale = ClassDesc.of("java.util.Locale").equals(methodType.parameterType(0));
+                formatArg = hasLocale ? 1 : 0;
+            } else {
+                hasLocale = ClassDesc.of("java.util.Locale").equals(methodType.parameterType(1));
+                formatArg = 0;
+            }
+
+            ConstantDesc<?> constantFormat = constantArgs[formatArg];
+
+            if (constantFormat == null) {
+                return new Result.None();
+            }
+
+            String bsmName = getBSMName(ownerDesc, methodName, isStatic, hasLocale);
+
+            MethodTypeDesc methodTypeLessFormat =
+                    methodType.dropParameterTypes(formatArg,  formatArg + 1);
+
+            return new Result.Indy(
+                    DynamicCallSiteDesc.of(
+                            ConstantDescs.ofCallsiteBootstrap(
+                                    ClassDesc.of("java.lang.invoke.IntrinsicFactory"),
+                                    bsmName,
+                                    ClassDesc.of("java.lang.invoke.CallSite")
+                            ),
+                            methodName,
+                            methodTypeLessFormat,
+                            new ConstantDesc<?>[]{constantFormat}),
+                    Intrinsics.dropArg(argClassDescs.length, formatArg)
+            );
+        }
+    }
+
+ }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/HashProcessorFactory.java	Wed Oct 31 11:08:50 2018 -0300
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+package com.sun.tools.javac.intrinsics;
+
+import java.lang.constant.ClassDesc;
+import java.lang.constant.ConstantDesc;
+import java.lang.constant.ConstantDescs;
+import java.lang.constant.DynamicCallSiteDesc;
+import java.lang.constant.MethodTypeDesc;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class HashProcessorFactory implements IntrinsicProcessorFactory {
+    @Override
+    public void register() {
+        Intrinsics.register(this,
+                Objects.class, "hash", int.class, Object[].class);
+    }
+
+    private static HashProcessor instance;
+
+    @Override
+    public IntrinsicProcessor processor() {
+        if (instance == null) {
+            instance = new HashProcessor();
+        }
+
+        return instance;
+    }
+
+    static class HashProcessor implements IntrinsicProcessor {
+        @Override
+        public Result tryIntrinsify(IntrinsicContext intrinsicContext,
+                                    ClassDesc ownerDesc,
+                                    String methodName,
+                                    MethodTypeDesc methodType,
+                                    boolean isStatic,
+                                    ClassDesc[] argClassDescs,
+                                    ConstantDesc<?>[] constantArgs) {
+            if (ClassDesc.of("java.util.Objects").equals(ownerDesc)) {
+                switch (methodName) {
+                    case "hash":
+                        if (Intrinsics.isAllConstants(constantArgs)) {
+                            Object[] constants =
+                                    Intrinsics.getConstants(argClassDescs, constantArgs);
+
+                            return new Result.Ldc(Arrays.hashCode(constants));
+                        } else {
+                            if (Intrinsics.isArrayVarArg(argClassDescs, 0)) {
+                                return new Result.None();
+                            }
+
+                            return new Result.Indy(
+                                    DynamicCallSiteDesc.of(
+                                            ConstantDescs.ofCallsiteBootstrap(
+                                                    ClassDesc.of("java.lang.invoke.IntrinsicFactory"),
+                                                    "objectsHashBootstrap",
+                                                    ClassDesc.of("java.lang.invoke.CallSite")
+                                            ),
+                                            methodName,
+                                            methodType,
+                                            new ConstantDesc<?>[0]),
+                                    argClassDescs.length
+                            );
+                        }
+                }
+            }
+
+            return new Result.None();
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/IntrinsicContext.java	Wed Oct 31 11:08:50 2018 -0300
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+package com.sun.tools.javac.intrinsics;
+
+import java.lang.constant.ClassDesc;
+import java.lang.constant.DirectMethodHandleDesc;
+
+/**
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public interface IntrinsicContext {
+    public void warning(String message);
+    public void warning(String message, int arg);
+    public void warning(String message, int arg, int offset);
+
+    public void error(String message);
+    public void error(String message, int arg);
+    public void error(String message, int arg, int offset);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/IntrinsicProcessor.java	Wed Oct 31 11:08:50 2018 -0300
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+package com.sun.tools.javac.intrinsics;
+
+import java.lang.constant.ClassDesc;
+import java.lang.constant.ConstantDesc;
+import java.lang.constant.DynamicCallSiteDesc;
+import java.lang.constant.MethodTypeDesc;
+
+/**
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public interface IntrinsicProcessor {
+    /**
+     *  <p><b>This is NOT part of any supported API.
+     *  If you write code that depends on this, you do so at your own risk.
+     *  This code and its internal interfaces are subject to change or
+     *  deletion without notice.</b>
+     */
+    public interface Result {
+        /**
+         *  <p><b>This is NOT part of any supported API.
+         *  If you write code that depends on this, you do so at your own risk.
+         *  This code and its internal interfaces are subject to change or
+         *  deletion without notice.</b>
+         */
+        public class None implements Result {
+        }
+
+        /**
+         *  <p><b>This is NOT part of any supported API.
+         *  If you write code that depends on this, you do so at your own risk.
+         *  This code and its internal interfaces are subject to change or
+         *  deletion without notice.</b>
+         */
+        public class Ldc implements Result {
+            private final ConstantDesc<?> constant;
+
+            /**
+             * <p><b>This is NOT part of any supported API.</b>
+             * @param constant  constant value result
+             */
+            public Ldc(ConstantDesc<?> constant) {
+                this.constant = constant;
+            }
+
+            /**
+             * <p><b>This is NOT part of any supported API.</b>
+             * @return constant result descriptor
+             */
+            public ConstantDesc<?> constant() {
+                return constant;
+            }
+        }
+
+        /**
+         *  <p><b>This is NOT part of any supported API.
+         *  If you write code that depends on this, you do so at your own risk.
+         *  This code and its internal interfaces are subject to change or
+         *  deletion without notice.</b>
+         */
+        public class Indy implements Result {
+            private final DynamicCallSiteDesc indy;
+            private final int[] args;
+
+            /**
+             * <p><b>This is NOT part of any supported API.</b>
+             * @param indy call site descriptor
+             * @param args indices of call arguments
+             */
+            public Indy(DynamicCallSiteDesc indy, int[] args) {
+                this.indy = indy;
+                this.args = args;
+            }
+
+            /**
+             * <p><b>This is NOT part of any supported API.</b>
+             * @param indy  call site descriptor
+             * @param nArgs argument range, 0..nArgs
+             */
+            public Indy(DynamicCallSiteDesc indy, int nArgs) {
+                this.indy = indy;
+                this.args = new int[nArgs];
+                for (int i = 0; i < nArgs; i++)
+                    args[i] = i;
+            }
+
+            /**
+             * <p><b>This is NOT part of any supported API.</b>
+             * @return DynamicCallSiteDesc value
+             */
+            public DynamicCallSiteDesc indy() {
+                return indy;
+            }
+
+            /**
+             * <p><b>This is NOT part of any supported API.</b>
+             * @return indices of call arguments
+             */
+            public int[] args() {
+                return args.clone();
+            }
+        }
+    }
+
+    /**
+     * <p><b>This is NOT part of any supported API.</b>
+     * @param ownerDesc       method owner
+     * @param methodName      method name
+     * @param methodType      method type descriptor
+     * @param isStatic        true if static method call
+     * @param argClassDescs   class descriptors for each argument (includes receiver)
+     * @param constantArgs    constant value for each argument (includes receiver), null means unknown
+     * @return IntrinsicProcessor.Result value
+     */
+    public Result tryIntrinsify(IntrinsicContext intrinsicContext,
+                                ClassDesc ownerDesc,
+                                String methodName,
+                                MethodTypeDesc methodType,
+                                boolean isStatic,
+                                ClassDesc[] argClassDescs,
+                                ConstantDesc<?>[] constantArgs);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/IntrinsicProcessorFactory.java	Wed Oct 31 11:08:50 2018 -0300
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+package com.sun.tools.javac.intrinsics;
+
+/**
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public interface IntrinsicProcessorFactory {
+    /**
+     * <p><b>This is NOT part of any supported API.</b>
+     */
+    public void register();
+
+    /**
+     * <p><b>This is NOT part of any supported API.</b>
+     * returns an IntrinsicProcessor instance
+     */
+    public IntrinsicProcessor processor();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/Intrinsics.java	Wed Oct 31 11:08:50 2018 -0300
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+package com.sun.tools.javac.intrinsics;
+
+import java.lang.constant.ClassDesc;
+import java.lang.constant.ConstantDesc;
+import java.lang.constant.ConstantDescs;
+import java.lang.constant.MethodTypeDesc;
+import java.lang.invoke.MethodHandles;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.ServiceLoader;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.util.stream.IntStream;
+
+/**
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class Intrinsics {
+     /** Registry map of available Intrinsic Processors */
+    static final Map<EntryKey, IntrinsicProcessorFactory> REGISTRY = new HashMap<>();
+    /** Lookup for resolving ConstantDesc */
+    static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
+
+    static {
+        ServiceLoader<IntrinsicProcessorFactory> serviceLoader =
+                ServiceLoader.load(IntrinsicProcessorFactory.class);
+        for (IntrinsicProcessorFactory ip : serviceLoader) {
+            ip.register();
+        }
+    }
+
+    static ClassDesc[] describeConstables(Class<?>[] types) {
+        int length = types.length;
+        ClassDesc[] classDescs = new ClassDesc[length];
+        for (int i = 0; i < length; i++) {
+            classDescs[i] = types[i].describeConstable().get();
+        }
+        return classDescs;
+    }
+
+    static class EntryKey {
+        final ClassDesc owner;
+        final String methodName;
+        final MethodTypeDesc methodType;
+
+        EntryKey(ClassDesc owner,
+                 String methodName,
+                 MethodTypeDesc methodType) {
+            this.owner = owner;
+            this.methodName = methodName;
+            this.methodType = methodType;
+         }
+
+        @Override
+        public boolean equals(Object other) {
+            if (this == other) {
+                return true;
+            }
+            if (other != null && other instanceof EntryKey) {
+                EntryKey otherKey = (EntryKey)other;
+                return owner.equals(otherKey.owner) &&
+                       methodName.equals(otherKey.methodName) &&
+                       methodType.equals(otherKey.methodType);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(owner, methodName, methodType);
+        }
+    }
+
+    static void register(IntrinsicProcessorFactory factory,
+                         Class<?> owner,
+                         String methodName,
+                         Class<?> returnType,
+                         Class<?>... argTypes) {
+        EntryKey key = new EntryKey(owner.describeConstable().get(),
+                                    methodName,
+                                    MethodTypeDesc.of(returnType.describeConstable().get(),
+                                                      describeConstables(argTypes)));
+        if (REGISTRY.put(key, factory) != null) {
+            assert false : "multiple entry: " + owner + methodName;
+        }
+    }
+
+    static Class<?> getClass(ClassDesc classDesc) {
+        try {
+            return classDesc.resolveConstantDesc(LOOKUP);
+        } catch (ReflectiveOperationException ex) {
+            // Fall thru
+        }
+        return null;
+    }
+
+    static Object getConstant(ConstantDesc<?> constantDesc) {
+        try {
+            return constantDesc.resolveConstantDesc(LOOKUP);
+        } catch (ReflectiveOperationException ex) {
+            // Fall thru
+        }
+        return null;
+    }
+
+    static Object getConstant(ClassDesc classDesc, ConstantDesc<?> constantDesc) {
+        try {
+            Object constant = constantDesc.resolveConstantDesc(LOOKUP);
+            if (ConstantDescs.CD_boolean.equals(classDesc) ||
+                    ConstantDescs.CD_Boolean.equals(classDesc)) {
+                int value = ((Number)constant).intValue();
+                constant = value == 0 ? Boolean.FALSE : Boolean.TRUE;
+            } else if (ConstantDescs.CD_byte.equals(classDesc) ||
+                    ConstantDescs.CD_Byte.equals(classDesc)) {
+                int value = ((Number)constant).intValue();
+                constant = (byte)value;
+            } else if (ConstantDescs.CD_short.equals(classDesc) ||
+                    ConstantDescs.CD_Short.equals(classDesc)) {
+                int value = ((Number)constant).intValue();
+                constant = (short)value;
+            } else if (ConstantDescs.CD_char.equals(classDesc) ||
+                    ConstantDescs.CD_Character.equals(classDesc)) {
+                int value = ((Number)constant).intValue();
+                constant = (char)value;
+            }
+            return constant;
+        } catch (ReflectiveOperationException ex) {
+            // Fall thru
+        }
+        return null;
+    }
+
+    static Object[] getConstants(ClassDesc[] classDescs,
+                                 ConstantDesc<?>[] constantDescs,
+                                 boolean skipReceiver) {
+        int length = constantDescs.length;
+        if (skipReceiver) {
+            Object[] constants = new Object[length - 1];
+            for (int i = 1; i < length; i++) {
+                constants[i - 1] = getConstant(classDescs[i], constantDescs[i]);
+            }
+            return constants;
+        } else {
+            Object[] constants = new Object[length];
+            for (int i = 0; i < length; i++) {
+                constants[i] = getConstant(classDescs[i], constantDescs[i]);
+            }
+            return constants;
+        }
+    }
+
+    static Object[] getConstants(ClassDesc[] classDescs,
+                                 ConstantDesc<?>[] constantDescs) {
+        return getConstants(classDescs, constantDescs, false);
+    }
+
+    static boolean isAllConstants(ConstantDesc<?>[] constantDescs, boolean skipReceiver) {
+        int length = constantDescs.length;
+        for (int i = skipReceiver ? 1 : 0; i < length; i++) {
+            if (constantDescs[i] == null) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    static boolean isAllConstants(ConstantDesc<?>[] constantDescs) {
+        return isAllConstants(constantDescs, false);
+    }
+
+    static boolean isArrayVarArg(ClassDesc[] argClassDescs, int i) {
+        return i + 1 == argClassDescs.length && argClassDescs[i].isArray();
+    }
+
+    static int[] dropArg(int n, int k) {
+        return IntStream.range(0, n)
+                        .filter(i -> i != k)
+                        .toArray();
+    }
+
+    static boolean checkRegex(IntrinsicContext intrinsicContext,
+                              ConstantDesc<?>[] constantArgs,
+                              int arg) {
+        if (constantArgs[arg] != null) {
+            try {
+                String regex = (String)constantArgs[arg];
+                Pattern.compile(regex);
+            } catch (PatternSyntaxException ex) {
+                intrinsicContext.warning("Syntax error in regular expression: " +
+                        ex.getMessage(), arg, ex.getIndex());
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * <p><b>This is NOT part of any supported API.</b>
+     * @param ownerDesc       method owner
+     * @param methodName      method name
+     * @param methodType      method type descriptor
+     * @return the intrinsic processor or null if not found
+     */
+    static public IntrinsicProcessorFactory getProcessorFactory(ClassDesc ownerDesc,
+                                                  String methodName,
+                                                  MethodTypeDesc methodType) {
+        EntryKey key = new EntryKey(ownerDesc, methodName, methodType);
+
+        return REGISTRY.get(key);
+    }
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/intrinsics/StringProcessorFactory.java	Wed Oct 31 11:08:50 2018 -0300
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+package com.sun.tools.javac.intrinsics;
+
+import java.lang.constant.ClassDesc;
+import java.lang.constant.ConstantDesc;
+import java.lang.constant.MethodTypeDesc;
+
+/**
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class StringProcessorFactory implements IntrinsicProcessorFactory {
+    @Override
+    public void register() {
+        Intrinsics.register(this,
+                String.class, "align", String.class);
+        Intrinsics.register(this,
+                String.class, "align", String.class, int.class);
+        Intrinsics.register(this,
+                String.class, "indent", String.class, int.class);
+        Intrinsics.register(this,
+                String.class, "length", int.class);
+        Intrinsics.register(this,
+                String.class, "matches", boolean.class, String.class);
+        Intrinsics.register(this,
+                String.class, "repeat", String.class, int.class);
+        Intrinsics.register(this,
+                String.class, "replaceAll", String.class, String.class, String.class);
+        Intrinsics.register(this,
+                String.class, "replaceFirst", String.class, String.class, String.class);
+        Intrinsics.register(this,
+                String.class, "split", String.class);
+        Intrinsics.register(this,
+                String.class, "split", String.class, int.class);
+        Intrinsics.register(this,
+                String.class, "strip", String.class);
+        Intrinsics.register(this,
+                String.class, "stripLeading", String.class);
+        Intrinsics.register(this,
+                String.class, "stripTrailing", String.class);
+    }
+
+    private static StringProcessor instance;
+
+    @Override
+    public IntrinsicProcessor processor() {
+        if (instance == null) {
+            instance = new StringProcessor();
+        }
+
+        return instance;
+    }
+
+    static class StringProcessor implements IntrinsicProcessor {
+        @Override
+        public Result tryIntrinsify(IntrinsicContext intrinsicContext,
+                                    ClassDesc ownerDesc,
+                                    String methodName,
+                                    MethodTypeDesc methodType,
+                                    boolean isStatic,
+                                    ClassDesc[] argClassDescs,
+                                    ConstantDesc<?>[] constantArgs) {
+            if (ClassDesc.of("java.lang.String").equals(ownerDesc)) {
+                // Compile time checks
+                switch (methodName) {
+                    case "matches":
+                    case "replaceAll":
+                    case "replaceFirst":
+                    case "split":
+                        if (!Intrinsics.checkRegex(intrinsicContext, constantArgs, 1)) {
+                            return new Result.None();
+                        }
+                        break;
+                }
+
+                // Fold when all arguments are constant
+                if (Intrinsics.isAllConstants(constantArgs)) {
+                    try {
+                        String string = (String)constantArgs[0];
+
+                        switch (methodName) {
+                            case "align": {
+                                if (constantArgs.length == 2) {
+                                    return new Result.Ldc(string.align((Integer)constantArgs[1]));
+                                } else {
+                                    return new Result.Ldc(string.align());
+                                }
+                            }
+                            case "indent": {
+                                return new Result.Ldc(string.indent((Integer)constantArgs[1]));
+                            }
+                            case "length": {
+                                 return new Result.Ldc(string.length());
+                            }
+                            case "repeat": {
+                                return new Result.Ldc(string.repeat((Integer)constantArgs[1]));
+                            }
+                            case "strip": {
+                                return new Result.Ldc(string.strip());
+                            }
+                            case "stripLeading": {
+                                return new Result.Ldc(string.stripLeading());
+                            }
+                            case "stripTrailing": {
+                                return new Result.Ldc(string.stripTrailing());
+                            }
+                        }
+                    } catch (Exception ex) {
+                        return new Result.None();
+                    }
+                }
+            }
+
+            return new Result.None();
+        }
+    }
+}
+
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Oct 31 11:08:50 2018 -0300
@@ -303,6 +303,10 @@
      */
     protected Flow flow;
 
+    /** The intrinsics analyzer.
+     */
+    protected IntrinsicsVisitor intrinsicsVisitor;
+
     /** The modules visitor
      */
     protected Modules modules;
@@ -415,6 +419,7 @@
         chk = Check.instance(context);
         gen = Gen.instance(context);
         flow = Flow.instance(context);
+        intrinsicsVisitor = IntrinsicsVisitor.instance(context);
         transTypes = TransTypes.instance(context);
         lower = Lower.instance(context);
         annotate = Annotate.instance(context);
@@ -1553,6 +1558,8 @@
             env.tree = transTypes.translateTopLevelClass(env.tree, localMake);
             compileStates.put(env, CompileState.TRANSTYPES);
 
+            env.tree = intrinsicsVisitor.analyzeTree(env.tree, env);
+
             if (Feature.LAMBDA.allowedInSource(source) && scanner.hasLambdas) {
                 if (shouldStop(CompileState.UNLAMBDA))
                     return;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Tue Oct 30 19:45:29 2018 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Oct 31 11:08:50 2018 -0300
@@ -800,6 +800,10 @@
 compiler.err.intf.not.allowed.here=\
     interface not allowed here
 
+# 0: string
+compiler.err.intrinsic.error=\
+    {0}
+
 compiler.err.enums.must.be.static=\
     enum declarations allowed only in static contexts
 
@@ -1753,6 +1757,10 @@
     cast to {0} for a varargs call\n\
     cast to {1} for a non-varargs call and to suppress this warning
 
+# 0: string
+compiler.warn.intrinsic.warning=\
+    {0}
+
 # 0: list of type
 compiler.warn.unreachable.catch=\
     unreachable catch clause\n\
--- a/src/jdk.compiler/share/classes/module-info.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/src/jdk.compiler/share/classes/module-info.java	Wed Oct 31 11:08:50 2018 -0300
@@ -134,5 +134,13 @@
 
     provides javax.tools.Tool with
         com.sun.tools.javac.api.JavacTool;
+
+    uses com.sun.tools.javac.intrinsics.IntrinsicProcessorFactory;
+
+    provides com.sun.tools.javac.intrinsics.IntrinsicProcessorFactory with
+        com.sun.tools.javac.intrinsics.FormatterProcessorFactory,
+        com.sun.tools.javac.intrinsics.HashProcessorFactory,
+        com.sun.tools.javac.intrinsics.StringProcessorFactory;
+
 }
 
--- a/test/jdk/java/util/Formatter/Basic-X.java.template	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/Basic-X.java.template	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 #if[datetime]
--- a/test/jdk/java/util/Formatter/BasicBigDecimal.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicBigDecimal.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicBigInteger.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicBigInteger.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicBoolean.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicBoolean.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicBooleanObject.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicBooleanObject.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicByte.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicByte.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicByteObject.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicByteObject.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicChar.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicChar.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicCharObject.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicCharObject.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicDateTime.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicDateTime.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicDouble.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicDouble.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicDoubleObject.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicDoubleObject.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicFloat.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicFloat.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicFloatObject.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicFloatObject.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicInt.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicInt.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicIntObject.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicIntObject.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicLong.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicLong.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicLongObject.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicLongObject.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicShort.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicShort.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/BasicShortObject.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/BasicShortObject.java	Wed Oct 31 11:08:50 2018 -0300
@@ -52,6 +52,9 @@
         f = new Formatter(new StringBuilder(), Locale.US);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, Locale.US, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", Locale.US, args);
     }
 
     private static void test(Locale l, String fs, String exp, Object ... args)
@@ -63,6 +66,9 @@
         f = new Formatter(new StringBuilder(), l);
         f.format("foo " + fs + " bar", args);
         ck(fs, "foo " + exp + " bar", f.toString());
+
+        JavacIntrinsicsSupport.formatAndCheck(fs, exp, l, args);
+        JavacIntrinsicsSupport.formatAndCheck("foo " + fs + " bar", "foo " + exp + " bar", l, args);
     }
 
     private static void test(String fs, Object ... args) {
@@ -110,6 +116,42 @@
                 fail(fs, ex.getClass());
             }
         }
+        testSysOutIntrinsic(fs, exp, args);
+    }
+
+    private static void testSysOutIntrinsic(String fs, String exp, Object ... args) {
+        FileOutputStream fos = null;
+        FileInputStream fis = null;
+        try {
+            PrintStream saveOut = System.out;
+            fos = new FileOutputStream("testSysOut");
+            System.setOut(new PrintStream(fos));
+            JavacIntrinsicsSupport.printStreamFormat(System.out, Locale.US, fs, args);
+            fos.close();
+
+            fis = new FileInputStream("testSysOut");
+            byte [] ba = new byte[exp.length()];
+            int len = fis.read(ba);
+            String got = new String(ba);
+            if (len != ba.length)
+                fail(fs, exp, got);
+            ck(fs, exp, got);
+
+            System.setOut(saveOut);
+        } catch (FileNotFoundException ex) {
+            fail(fs, ex.getClass());
+        } catch (IOException ex) {
+            fail(fs, ex.getClass());
+        } finally {
+            try {
+                if (fos != null)
+                    fos.close();
+                if (fis != null)
+                    fis.close();
+            } catch (IOException ex) {
+                fail(fs, ex.getClass());
+            }
+        }
     }
 
     private static void tryCatch(String fs, Class<?> ex) {
@@ -124,6 +166,8 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex);
     }
 
     private static void tryCatch(String fs, Class<?> ex, Object ... args) {
@@ -138,6 +182,36 @@
             fail(fs, ex);
         else
             pass();
+
+        tryCatchIntrinsic(fs, ex, args);
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, "fail");
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
+    }
+
+    private static void tryCatchIntrinsic(String fs, Class<?> ex, Object ... args) {
+        boolean caught = false;
+        try {
+            JavacIntrinsicsSupport.formatAndCheck(fs, "fail", Locale.US, args);
+        } catch (Throwable x) {
+            if (ex.isAssignableFrom(x.getClass()))
+                caught = true;
+        }
+        if (!caught)
+            fail(fs, ex);
+        else
+            pass();
     }
 
 
--- a/test/jdk/java/util/Formatter/EncodingTest.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/EncodingTest.java	Wed Oct 31 11:08:50 2018 -0300
@@ -91,6 +91,26 @@
                 Files.readAllLines(Paths.get(file2.getPath()), charset));
     }
 
+
+    /**
+     * Verifies that the overloading constructor behaves the same as the existing
+     * one.
+     * @param type the type of the constructor
+     * @param file1 file1 written with the name of a charset
+     * @param file2 file2 written with a charset
+     * @param csn the charset name
+     * @param charset the charset
+     * @throws IOException
+     */
+    @Test(dataProvider = "parameters")
+    public void testConstructorIntrinsic(ConstructorType type, File file1, File file2,
+                                String csn, Charset charset) throws Exception {
+        formatIntrinsic(getFormatter(type, file1.getPath(), csn, null));
+        formatIntrinsic(getFormatter(type, file2.getPath(), null, charset));
+        Assert.assertEquals(Files.readAllLines(Paths.get(file1.getPath()), charset),
+                Files.readAllLines(Paths.get(file2.getPath()), charset));
+    }
+
     void format(Formatter formatter)
             throws IOException {
         formatter.format("abcde \u00FA\u00FB\u00FC\u00FD");
@@ -99,6 +119,14 @@
         formatter.close();
     }
 
+    void formatIntrinsic(Formatter formatter)
+            throws IOException {
+        JavacIntrinsicsSupport.format(formatter, "abcde \u00FA\u00FB\u00FC\u00FD");
+        JavacIntrinsicsSupport.format(formatter, "Java \uff08\u8ba1\u7b97\u673a\u7f16\u7a0b\u8bed\u8a00\uff09");
+        formatter.flush();
+        formatter.close();
+    }
+
 
     Formatter getFormatter(ConstructorType type, String path, String csn, Charset charset)
             throws IOException {
--- a/test/jdk/java/util/Formatter/FormatLocale.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/FormatLocale.java	Wed Oct 31 11:08:50 2018 -0300
@@ -107,6 +107,19 @@
                                 "'. Expected: " + expectedWithDefaultLocale.get(i) +
                                 " Returned: " + sb.toString());
             }
+
+            sb.setLength(0);
+            JavacIntrinsicsSupport.format(new Formatter(sb), conversions.get(i), src.get(i));
+            if (!sb.toString().equals(expectedWithDefaultLocale.get(i))) {
+                throw new RuntimeException(
+                        "Wrong uppercasing while using Formatter.format(" +
+                                "\"" + conversions.get(i) + "\"" +
+                                ") with the default locale: '"
+                                + defaultLocale.get(i) +
+                                "'. Expected: " + expectedWithDefaultLocale.get(i) +
+                                " Returned: " + sb.toString());
+            }
+
         });
 
         // checks whether upper casing uses the locale set during creation of
@@ -125,6 +138,18 @@
                                 "'. Expected: " + expectedWithFormatLocale.get(i) +
                                 " Returned: " + sb.toString());
             }
+
+            sb.setLength(0);
+            JavacIntrinsicsSupport.format(new Formatter(sb, formatLocale.get(i)), conversions.get(i), src.get(i));
+            if (!sb.toString().equals(expectedWithFormatLocale.get(i))) {
+                throw new RuntimeException(
+                        "Wrong uppercasing while using Formatter.format(" +
+                                "\"" + conversions.get(i) + "\"" +
+                                ") with the locale specified during instance" +
+                                " creation: '" + formatLocale.get(i) +
+                                "'. Expected: " + expectedWithFormatLocale.get(i) +
+                                " Returned: " + sb.toString());
+            }
         });
 
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/Formatter/JavacIntrinsicsSupport.java	Wed Oct 31 11:08:50 2018 -0300
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+import java.io.PrintStream;
+import java.lang.invoke.CallSite;
+import java.lang.invoke.FormatterBootstraps;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Locale;
+
+public class JavacIntrinsicsSupport extends Basic {
+
+
+    static void formatAndCheck(String fs, String exp, Locale l, Object... args) {
+        try {
+
+            CallSite cs = FormatterBootstraps.formatterBootstrap(MethodHandles.lookup(), "format",
+                    getFormatterFormatMethodType(args), fs, false, false);
+            Formatter f = new Formatter(new StringBuilder(), l);
+            List<Object> invokeArgs = new ArrayList<>();
+            invokeArgs.add(f);
+            if (args != null) {
+                Collections.addAll(invokeArgs, args);
+            } else {
+                invokeArgs.add(null);
+            }
+            cs.dynamicInvoker().invokeWithArguments(invokeArgs);
+            ck(fs, exp, f.toString());
+
+        } catch (RuntimeException rt) {
+            throw rt;
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
+    }
+
+    static void format(Formatter f, String fs, Object... args) {
+        try {
+
+            CallSite cs = FormatterBootstraps.formatterBootstrap(MethodHandles.lookup(), "format",
+                    getFormatterFormatMethodType(args), fs, false, false);
+            List<Object> invokeArgs = new ArrayList<>();
+            invokeArgs.add(f);
+            if (args != null) {
+                Collections.addAll(invokeArgs, args);
+            } else {
+                invokeArgs.add(null);
+            }
+            cs.dynamicInvoker().invokeWithArguments(invokeArgs);
+
+        } catch (RuntimeException rt) {
+            throw rt;
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
+    }
+
+    static String stringFormat(String fs, Object... args) {
+        try {
+
+            CallSite cs = FormatterBootstraps.formatterBootstrap(MethodHandles.lookup(), "format",
+                    getStringFormatMethodType(args), fs, true, false);
+            List<Object> invokeArgs = new ArrayList<>();
+            if (args != null) {
+                Collections.addAll(invokeArgs, args);
+            } else {
+                invokeArgs.add(null);
+            }
+            return (String) cs.dynamicInvoker().invokeWithArguments(invokeArgs);
+
+        } catch (RuntimeException rt) {
+            throw rt;
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
+    }
+
+    static PrintStream printStreamFormat(PrintStream ps, Locale l, String fs, Object... args) {
+        try {
+
+            CallSite cs = FormatterBootstraps.formatterBootstrap(MethodHandles.lookup(), "format",
+                    getPrintStreamFormatMethodType(args), fs, false, true);
+            List<Object> invokeArgs = new ArrayList<>();
+            invokeArgs.add(ps);
+            invokeArgs.add(l);
+            if (args != null) {
+                Collections.addAll(invokeArgs, args);
+            } else {
+                invokeArgs.add(null);
+            }
+            return (PrintStream) cs.dynamicInvoker().invokeWithArguments(invokeArgs);
+
+        } catch (RuntimeException rt) {
+            throw rt;
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
+    }
+
+    private static MethodType getFormatterFormatMethodType(Object... args) {
+        MethodType mt = MethodType.methodType(Formatter.class, Formatter.class);
+        if (args != null) {
+            for (Object arg : args) {
+                mt = mt.appendParameterTypes(arg == null ? Object.class : arg.getClass());
+            }
+        } else {
+            mt = mt.appendParameterTypes(Object[].class);
+        }
+        return mt;
+    }
+
+    private static MethodType getStringFormatMethodType(Object... args) {
+        MethodType mt = MethodType.methodType(String.class);
+        if (args != null) {
+            for (Object arg : args) {
+                mt = mt.appendParameterTypes(arg == null ? Object.class : arg.getClass());
+            }
+        } else {
+            mt = mt.appendParameterTypes(Object[].class);
+        }
+        return mt;
+    }
+
+    private static MethodType getPrintStreamFormatMethodType(Object... args) {
+        MethodType mt = MethodType.methodType(PrintStream.class, PrintStream.class, Locale.class);
+        if (args != null) {
+            for (Object arg : args) {
+                mt = mt.appendParameterTypes(arg == null ? Object.class : arg.getClass());
+            }
+        } else {
+            mt = mt.appendParameterTypes(Object[].class);
+        }
+        return mt;
+    }
+}
--- a/test/jdk/java/util/Formatter/NullArg.java	Tue Oct 30 19:45:29 2018 +0100
+++ b/test/jdk/java/util/Formatter/NullArg.java	Wed Oct 31 11:08:50 2018 -0300
@@ -27,7 +27,6 @@
  * @summary Basic test for null argument
  */
 
-import java.util.Formatter;
 import java.util.Locale;
 
 public class NullArg {
@@ -52,11 +51,17 @@
                     if (!String.format("%" + c + ct, null).equals(expected)) {
                         throw new RuntimeException("%t" + ct + "null check failed.");
                     }
+                    if (!JavacIntrinsicsSupport.stringFormat("%" + c + ct, null).equals(expected)) {
+                        throw new RuntimeException("%t" + ct + "null check failed. " + JavacIntrinsicsSupport.stringFormat("%" + c + ct, null) + " // " + expected);
+                    }
                 }
             } else {
                 if (!String.format("%" + c , null).equals(expected)) {
                     throw new RuntimeException("%" + c + "null check failed.");
                 }
+                if (!JavacIntrinsicsSupport.stringFormat("%" + c , null).equals(expected)) {
+                    throw new RuntimeException("%" + c + "null check failed. " + JavacIntrinsicsSupport.stringFormat("%" + c , null) + " // " + expected);
+                }
             }
         }
     }