From 71681ac4cbac84c196b3b2ed482d1b608ae30ca2 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Mon, 1 Feb 2016 15:00:02 -0800 Subject: [PATCH 001/183] 8148628: TIFFDirectory(getAsMetaData) created with one TIFFField having a IFD pointer tag throws ClassCastException & other naming differences (JEP 262) Clean up some handling of TIFFDirectory instances contained in TIFFFields and make a couple of minor changes to Exif and GeoTIFF tag names. Reviewed-by: prr --- .../imageio/plugins/tiff/TIFFFieldNode.java | 13 ++++++----- .../imageio/plugins/tiff/ExifTIFFTagSet.java | 4 ++-- .../imageio/plugins/tiff/GeoTIFFTagSet.java | 8 +++---- .../imageio/plugins/tiff/TIFFDirectory.java | 22 ++++++++++++++----- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java index ced248f9d7e..e78954b34e4 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -39,7 +39,7 @@ import javax.imageio.plugins.tiff.TIFFTagSet; */ public class TIFFFieldNode extends IIOMetadataNode { private static String getNodeName(TIFFField f) { - return f.getData() instanceof TIFFDirectory ? + return (f.hasDirectory() || f.getData() instanceof TIFFDirectory) ? "TIFFIFD" : "TIFFField"; } @@ -52,7 +52,8 @@ public class TIFFFieldNode extends IIOMetadataNode { public TIFFFieldNode(TIFFField field) { super(getNodeName(field)); - isIFD = field.getData() instanceof TIFFDirectory; + isIFD = field.hasDirectory() || + field.getData() instanceof TIFFDirectory; this.field = field; @@ -68,7 +69,8 @@ public class TIFFFieldNode extends IIOMetadataNode { setAttribute("parentTagName", tagName); } - TIFFDirectory dir = (TIFFDirectory)field.getData(); + TIFFDirectory dir = field.hasDirectory() ? + field.getDirectory() : (TIFFDirectory)field.getData(); TIFFTagSet[] tagSets = dir.getTagSets(); if(tagSets != null) { StringBuilder tagSetNames = new StringBuilder(); @@ -90,7 +92,8 @@ public class TIFFFieldNode extends IIOMetadataNode { if(isInitialized) return; if(isIFD) { - TIFFDirectory dir = (TIFFDirectory)field.getData(); + TIFFDirectory dir = field.hasDirectory() ? + field.getDirectory() : (TIFFDirectory)field.getData(); TIFFField[] fields = dir.getTIFFFields(); if(fields != null) { TIFFTagSet[] tagSets = dir.getTagSets(); diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java index 5867a0ffef5..792a78fcb23 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -1256,7 +1256,7 @@ public class ExifTIFFTagSet extends TIFFTagSet { static class ExifVersion extends TIFFTag { public ExifVersion() { - super("Exifversion", + super("ExifVersion", TAG_EXIF_VERSION, 1 << TIFFTag.TIFF_UNDEFINED, 4); diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java index c478f7c03e7..ec6e5f2a503 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -97,7 +97,7 @@ public class GeoTIFFTagSet extends TIFFTagSet { static class GeoKeyDirectory extends TIFFTag { public GeoKeyDirectory() { - super("GeoKeyDirectory", + super("GeoKeyDirectoryTag", TAG_GEO_KEY_DIRECTORY, 1 << TIFFTag.TIFF_SHORT); } @@ -105,7 +105,7 @@ public class GeoTIFFTagSet extends TIFFTagSet { static class GeoDoubleParams extends TIFFTag { public GeoDoubleParams() { - super("GeoDoubleParams", + super("GeoDoubleParamsTag", TAG_GEO_DOUBLE_PARAMS, 1 << TIFFTag.TIFF_DOUBLE); } @@ -113,7 +113,7 @@ public class GeoTIFFTagSet extends TIFFTagSet { static class GeoAsciiParams extends TIFFTag { public GeoAsciiParams() { - super("GeoAsciiParams", + super("GeoAsciiParamsTag", TAG_GEO_ASCII_PARAMS, 1 << TIFFTag.TIFF_ASCII); } diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java index ea13664767c..7f75db646db 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -219,11 +219,23 @@ public class TIFFDirectory implements Cloneable { TIFFField f = fields[i]; TIFFTag tag = f.getTag(); if(tag.isIFDPointer()) { - TIFFDirectory subIFD = - getDirectoryAsIFD((TIFFDirectory)f.getData()); - f = new TIFFField(tag, f.getType(), (long)f.getCount(), subIFD); + TIFFDirectory subDir = null; + if (f.hasDirectory()) { + subDir = f.getDirectory(); + } else if (f.getData() instanceof TIFFDirectory) { + subDir = (TIFFDirectory)f.getData(); + } + if (subDir != null) { + TIFFDirectory subIFD = getDirectoryAsIFD(subDir); + f = new TIFFField(tag, f.getType(), (long)f.getCount(), + subIFD); + } else { + f = null; + } + } + if (f != null) { + ifd.addTIFFField(f); } - ifd.addTIFFField(f); } return ifd; From b1ccba1fcb087e011877017e6e10077bd4fca31f Mon Sep 17 00:00:00 2001 From: Alexander Scherbatiy Date: Thu, 11 Feb 2016 00:19:38 +0400 Subject: [PATCH 002/183] 8139508: Debug option does not work in appletviewer Reviewed-by: prr, ssadetsky --- .../share/classes/sun/applet/Main.java | 76 ------------------- .../sun/applet/resources/MsgAppletViewer.java | 2 +- 2 files changed, 1 insertion(+), 77 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/sun/applet/Main.java b/jdk/src/java.desktop/share/classes/sun/applet/Main.java index 681fb81c6db..086b1113614 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/Main.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/Main.java @@ -30,8 +30,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.net.MalformedURLException; import java.util.Enumeration; @@ -75,7 +73,6 @@ public class Main { /** * Member variables set according to options passed in to AppletViewer. */ - private boolean debugFlag = false; private boolean helpFlag = false; private String encoding = null; private boolean noSecurityFlag = false; @@ -136,14 +133,6 @@ public class Main { return 1; } - if (debugFlag) { - // START A DEBUG SESSION - // Given the current architecture, we will end up decoding the - // arguments again, but at least we are guaranteed to have - // arguments which are valid. - return invokeDebugger(args); - } - // INSTALL THE SECURITY MANAGER (if necessary) if (!noSecurityFlag && (System.getSecurityManager() == null)) init(); @@ -191,9 +180,6 @@ public class Main { throw new ParseException(lookup("main.err.dupoption", arg)); encoding = args[++i]; return 2; - } else if ("-debug".equals(arg)) { - debugFlag = true; - return 1; } else if ("-Xnosecurity".equals(arg)) { // This is an undocumented (and, in the future, unsupported) // flag which prevents AppletViewer from installing its own @@ -267,68 +253,6 @@ public class Main { return u; } - /** - * Invoke the debugger with the arguments passed in to appletviewer. - * - * @param args The arguments passed into the debugger. - * @return {@code 0} if the debugger is invoked successfully, - * {@code 1} otherwise. - */ - private int invokeDebugger(String [] args) { - // CONSTRUCT THE COMMAND LINE - String [] newArgs = new String[args.length + 1]; - int current = 0; - - // Add a -classpath argument that prevents - // the debugger from launching appletviewer with the default of - // ".". appletviewer's classpath should never contain valid - // classes since they will result in security exceptions. - // Ideally, the classpath should be set to "", but the VM won't - // allow an empty classpath, so a phony directory name is used. - String phonyDir = System.getProperty("java.home") + - File.separator + "phony"; - newArgs[current++] = "-Djava.class.path=" + phonyDir; - - // Appletviewer's main class is the debuggee - newArgs[current++] = "sun.applet.Main"; - - // Append all the of the original appletviewer arguments, - // leaving out the "-debug" option. - for (int i = 0; i < args.length; i++) { - if (!("-debug".equals(args[i]))) { - newArgs[current++] = args[i]; - } - } - - // LAUNCH THE DEBUGGER - // Reflection is used for two reasons: - // 1) The debugger classes are on classpath and thus must be loaded - // by the application class loader. (Currently, appletviewer are - // loaded through the boot class path out of rt.jar.) - // 2) Reflection removes any build dependency between appletviewer - // and jdb. - try { - Class c = Class.forName("com.sun.tools.example.debug.tty.TTY", true, - ClassLoader.getSystemClassLoader()); - Method m = c.getDeclaredMethod("main", - new Class[] { String[].class }); - m.invoke(null, new Object[] { newArgs }); - } catch (ClassNotFoundException cnfe) { - System.err.println(lookup("main.debug.cantfinddebug")); - return 1; - } catch (NoSuchMethodException nsme) { - System.err.println(lookup("main.debug.cantfindmain")); - return 1; - } catch (InvocationTargetException ite) { - System.err.println(lookup("main.debug.exceptionindebug")); - return 1; - } catch (IllegalAccessException iae) { - System.err.println(lookup("main.debug.cantaccess")); - return 1; - } - return 0; - } - private void init() { // GET APPLETVIEWER USER-SPECIFIC PROPERTIES Properties avProps = getAVProps(); diff --git a/jdk/src/java.desktop/share/classes/sun/applet/resources/MsgAppletViewer.java b/jdk/src/java.desktop/share/classes/sun/applet/resources/MsgAppletViewer.java index f05729b972e..2b2bf2de74f 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/resources/MsgAppletViewer.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/resources/MsgAppletViewer.java @@ -74,7 +74,7 @@ public class MsgAppletViewer extends ListResourceBundle { {"appletviewer.parse.warning.embed.requireswidth", "Warning: tag requires width attribute."}, {"appletviewer.parse.warning.appnotLongersupported", "Warning: tag no longer supported, use instead:"}, {"appletviewer.deprecated", "AppletViewer is deprecated."}, - {"appletviewer.usage", "Usage: appletviewer url(s)\n\nwhere include:\n -debug Start the applet viewer in the Java debugger\n -encoding Specify character encoding used by HTML files\n -J Pass argument to the java interpreter\n\nThe -J option is non-standard and subject to change without notice."}, + {"appletviewer.usage", "Usage: appletviewer url(s)\n\nwhere include:\n -encoding Specify character encoding used by HTML files\n -J Pass argument to the java interpreter\n\nThe -J option is non-standard and subject to change without notice."}, {"appletviewer.main.err.unsupportedopt", "Unsupported option: {0}"}, {"appletviewer.main.err.unrecognizedarg", "Unrecognized argument: {0}"}, {"appletviewer.main.err.dupoption", "Duplicate use of option: {0}"}, From a99085b4db9f5c6448637e257066ee128bbc34d8 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 10 Feb 2016 13:49:06 -0800 Subject: [PATCH 003/183] 8149120: TIFFField constructor throws ArrayIndexOutOfBoundsException and IllegalArgumentException for scenarios explained in description Clean up parameter checking in TIFFField. Reviewed-by: prr --- .../javax/imageio/plugins/tiff/TIFFField.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java index 7afc44520f9..010f841315b 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java @@ -519,6 +519,11 @@ public class TIFFField implements Cloneable { * @throws IllegalArgumentException if type is an unacceptable * data type for the supplied TIFFTag. * @throws IllegalArgumentException if count < 0. + * @throws IllegalArgumentException if count < 1 + * and type is TIFF_RATIONAL or + * TIFF_SRATIONAL. + * @throws IllegalArgumentException if count ≠ 1 + * and type is TIFF_IFD_POINTER. * @throws NullPointerException if data == null. * @throws IllegalArgumentException if data is an instance of * a class incompatible with the specified type. @@ -534,6 +539,14 @@ public class TIFFField implements Cloneable { + " for " + tag.getName() + " tag"); } else if(count < 0) { throw new IllegalArgumentException("count < 0!"); + } else if((type == TIFFTag.TIFF_RATIONAL + || type == TIFFTag.TIFF_SRATIONAL) + && count < 1) { + throw new IllegalArgumentException + ("Type is TIFF_RATIONAL or TIFF_SRATIONAL and count < 1"); + } else if (type == TIFFTag.TIFF_IFD_POINTER && count != 1) { + throw new IllegalArgumentException + ("Type is TIFF_IFD_POINTER count != 1"); } else if(data == null) { throw new NullPointerException("data == null!"); } From 073470bedbb36f543f9015df4b473621465896d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Bourg=C3=A8s?= Date: Thu, 11 Feb 2016 09:08:15 +0100 Subject: [PATCH 004/183] 8149338: JVM Crash caused by Marlin renderer not handling NaN coordinates Use first / last Y crossings to compute edge min/max Y and ensure consistency with edgeBuckets / edgeBucketCounts arrays Reviewed-by: flar, prr --- .../classes/sun/java2d/marlin/Renderer.java | 55 ++++--- jdk/test/sun/java2d/marlin/CrashNaNTest.java | 143 ++++++++++++++++++ .../sun/java2d/marlin/TextClipErrorTest.java | 22 +-- 3 files changed, 178 insertions(+), 42 deletions(-) create mode 100644 jdk/test/sun/java2d/marlin/CrashNaNTest.java diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java index aacd8b2062d..cd063867280 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java @@ -148,8 +148,8 @@ final class Renderer implements PathConsumer2D, MarlinConst { ////////////////////////////////////////////////////////////////////////////// // EDGE LIST ////////////////////////////////////////////////////////////////////////////// - private float edgeMinY = Float.POSITIVE_INFINITY; - private float edgeMaxY = Float.NEGATIVE_INFINITY; + private int edgeMinY = Integer.MAX_VALUE; + private int edgeMaxY = Integer.MIN_VALUE; private float edgeMinX = Float.POSITIVE_INFINITY; private float edgeMaxX = Float.NEGATIVE_INFINITY; @@ -357,18 +357,21 @@ final class Renderer implements PathConsumer2D, MarlinConst { } return; } - // edge min/max X/Y are in subpixel space (inclusive) - if (y1 < edgeMinY) { - edgeMinY = y1; + + // edge min/max X/Y are in subpixel space (inclusive) within bounds: + // note: Use integer crossings to ensure consistent range within + // edgeBuckets / edgeBucketCounts arrays in case of NaN values (int = 0) + if (firstCrossing < edgeMinY) { + edgeMinY = firstCrossing; } - if (y2 > edgeMaxY) { - edgeMaxY = y2; + if (lastCrossing > edgeMaxY) { + edgeMaxY = lastCrossing; } // Use double-precision for improved accuracy: final double x1d = x1; final double y1d = y1; - final double slope = (x2 - x1d) / (y2 - y1d); + final double slope = (x1d - x2) / (y1d - y2); if (slope >= 0.0) { // <==> x1 < x2 if (x1 < edgeMinX) { @@ -504,7 +507,7 @@ final class Renderer implements PathConsumer2D, MarlinConst { private float x0, y0; // Position of most recent 'moveTo' command - private float pix_sx0, pix_sy0; + private float sx0, sy0; // per-thread renderer context final RendererContext rdrCtx; @@ -570,8 +573,8 @@ final class Renderer implements PathConsumer2D, MarlinConst { edgeBucketCounts = rdrCtx.getIntArray(edgeBucketsLength); } - edgeMinY = Float.POSITIVE_INFINITY; - edgeMaxY = Float.NEGATIVE_INFINITY; + edgeMinY = Integer.MAX_VALUE; + edgeMaxY = Integer.MIN_VALUE; edgeMinX = Float.POSITIVE_INFINITY; edgeMaxX = Float.NEGATIVE_INFINITY; @@ -628,7 +631,7 @@ final class Renderer implements PathConsumer2D, MarlinConst { blkFlags = blkFlags_initial; } - if (edgeMinY != Float.POSITIVE_INFINITY) { + if (edgeMinY != Integer.MAX_VALUE) { // if context is maked as DIRTY: if (rdrCtx.dirty) { // may happen if an exception if thrown in the pipeline processing: @@ -688,16 +691,18 @@ final class Renderer implements PathConsumer2D, MarlinConst { @Override public void moveTo(float pix_x0, float pix_y0) { closePath(); - this.pix_sx0 = pix_x0; - this.pix_sy0 = pix_y0; - this.y0 = tosubpixy(pix_y0); - this.x0 = tosubpixx(pix_x0); + final float sx = tosubpixx(pix_x0); + final float sy = tosubpixy(pix_y0); + this.sx0 = sx; + this.sy0 = sy; + this.x0 = sx; + this.y0 = sy; } @Override public void lineTo(float pix_x1, float pix_y1) { - float x1 = tosubpixx(pix_x1); - float y1 = tosubpixy(pix_y1); + final float x1 = tosubpixx(pix_x1); + final float y1 = tosubpixy(pix_y1); addLine(x0, y0, x1, y1); x0 = x1; y0 = y1; @@ -729,8 +734,9 @@ final class Renderer implements PathConsumer2D, MarlinConst { @Override public void closePath() { - // lineTo expects its input in pixel coordinates. - lineTo(pix_sx0, pix_sy0); + addLine(x0, y0, sx0, sy0); + x0 = sx0; + y0 = sy0; } @Override @@ -1396,7 +1402,7 @@ final class Renderer implements PathConsumer2D, MarlinConst { if (doMonitors) { RendererContext.stats.mon_rdr_endRendering.start(); } - if (edgeMinY == Float.POSITIVE_INFINITY) { + if (edgeMinY == Integer.MAX_VALUE) { return false; // undefined edges bounds } @@ -1407,11 +1413,10 @@ final class Renderer implements PathConsumer2D, MarlinConst { final int spminX = FloatMath.max(FloatMath.ceil_int(edgeMinX - 0.5f), boundsMinX); final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5f), boundsMaxX - 1); - // y1 (and y2) are already biased by -0.5 in tosubpixy(): - final int spminY = FloatMath.max(FloatMath.ceil_int(edgeMinY), _boundsMinY); - int maxY = FloatMath.ceil_int(edgeMaxY); - + // edge Min/Max Y are already rounded to subpixels within bounds: + final int spminY = edgeMinY; final int spmaxY; + int maxY = edgeMaxY; if (maxY <= _boundsMaxY - 1) { spmaxY = maxY; diff --git a/jdk/test/sun/java2d/marlin/CrashNaNTest.java b/jdk/test/sun/java2d/marlin/CrashNaNTest.java new file mode 100644 index 00000000000..01e32dd6c11 --- /dev/null +++ b/jdk/test/sun/java2d/marlin/CrashNaNTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2016, 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.awt.Color; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.geom.Path2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import static java.lang.Double.NaN; +import java.util.Locale; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import javax.imageio.ImageIO; + +/** + * @test + * @bug 8149338 + * @summary Verifies that Marlin supports NaN coordinates and no JVM crash happens ! + * @run main CrashNaNTest + */ +public class CrashNaNTest { + + static final boolean SAVE_IMAGE = false; + + public static void main(String argv[]) { + Locale.setDefault(Locale.US); + + // initialize j.u.l Looger: + final Logger log = Logger.getLogger("sun.java2d.marlin"); + log.addHandler(new Handler() { + @Override + public void publish(LogRecord record) { + Throwable th = record.getThrown(); + // detect any Throwable: + if (th != null) { + System.out.println("Test failed:\n" + record.getMessage()); + th.printStackTrace(System.out); + + throw new RuntimeException("Test failed: ", th); + } + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + }); + + // enable Marlin logging & internal checks: + System.setProperty("sun.java2d.renderer.log", "true"); + System.setProperty("sun.java2d.renderer.useLogger", "true"); + System.setProperty("sun.java2d.renderer.doChecks", "true"); + + final int width = 400; + final int height = 400; + + final BufferedImage image = new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB); + + final Graphics2D g2d = (Graphics2D) image.getGraphics(); + try { + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + g2d.setBackground(Color.WHITE); + g2d.clearRect(0, 0, width, height); + + final Path2D.Double path = new Path2D.Double(); + path.moveTo(30, 30); + path.lineTo(100, 100); + + for (int i = 0; i < 20000; i++) { + path.lineTo(110 + 0.01 * i, 110); + path.lineTo(111 + 0.01 * i, 100); + } + + path.lineTo(NaN, 200); + path.lineTo(200, 200); + path.lineTo(200, NaN); + path.lineTo(300, 300); + path.lineTo(NaN, NaN); + path.lineTo(100, 100); + path.closePath(); + + final Path2D.Double path2 = new Path2D.Double(); + path2.moveTo(0,0); + path2.lineTo(width,height); + path2.lineTo(10, 10); + path2.closePath(); + + for (int i = 0; i < 1; i++) { + final long start = System.nanoTime(); + g2d.setColor(Color.BLUE); + g2d.fill(path); + + g2d.fill(path2); + + final long time = System.nanoTime() - start; + System.out.println("paint: duration= " + (1e-6 * time) + " ms."); + } + + if (SAVE_IMAGE) { + try { + final File file = new File("CrashNaNTest.png"); + System.out.println("Writing file: " + + file.getAbsolutePath()); + ImageIO.write(image, "PNG", file); + } catch (IOException ex) { + System.out.println("Writing file failure:"); + ex.printStackTrace(); + } + } + } finally { + g2d.dispose(); + } + } +} diff --git a/jdk/test/sun/java2d/marlin/TextClipErrorTest.java b/jdk/test/sun/java2d/marlin/TextClipErrorTest.java index efce137256c..c6d42ceb305 100644 --- a/jdk/test/sun/java2d/marlin/TextClipErrorTest.java +++ b/jdk/test/sun/java2d/marlin/TextClipErrorTest.java @@ -69,24 +69,12 @@ public class TextClipErrorTest { @Override public void publish(LogRecord record) { Throwable th = record.getThrown(); - // detect potential Throwable thrown by XxxArrayCache.check(): - if (th != null && th.getClass() == Throwable.class) { - StackTraceElement[] stackElements = th.getStackTrace(); + // detect any Throwable: + if (th != null) { + System.out.println("Test failed:\n" + record.getMessage()); + th.printStackTrace(System.out); - for (int i = 0; i < stackElements.length; i++) { - StackTraceElement e = stackElements[i]; - - if (e.getClassName().startsWith("sun.java2d.marlin") - && e.getClassName().contains("ArrayCache") - && "check".equals(e.getMethodName())) - { - System.out.println("Test failed:\n" - + record.getMessage()); - th.printStackTrace(System.out); - - throw new RuntimeException("Test failed: ", th); - } - } + throw new RuntimeException("Test failed: ", th); } } From 5b56cd34c174414d624ea333d0a0ece66c522ace Mon Sep 17 00:00:00 2001 From: Vikrant Agarwal Date: Thu, 11 Feb 2016 12:24:28 +0300 Subject: [PATCH 005/183] 8131751: [TEST_BUG] Test javax/swing/plaf/gtk/crash/RenderBadPictureCrash.java fails UnsupportedOperationException Reviewed-by: alexsch, ssadetsky --- .../swing/plaf/gtk/crash/RenderBadPictureCrash.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/jdk/test/javax/swing/plaf/gtk/crash/RenderBadPictureCrash.java b/jdk/test/javax/swing/plaf/gtk/crash/RenderBadPictureCrash.java index 0ef16996cf5..71a2e6f4b58 100644 --- a/jdk/test/javax/swing/plaf/gtk/crash/RenderBadPictureCrash.java +++ b/jdk/test/javax/swing/plaf/gtk/crash/RenderBadPictureCrash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,16 +23,15 @@ /* @test - @bug 8056151 + @bug 8056151 8131751 @summary Switching to GTK L&F on-the-fly leads to X Window System error RenderBadPicture @run main/othervm -Dswing.defaultlaf=javax.swing.plaf.metal.MetalLookAndFeel -Dsun.java2d.xrender=T RenderBadPictureCrash */ - import java.awt.Color; +import java.awt.GraphicsDevice; import java.lang.reflect.InvocationTargetException; import javax.swing.JFrame; import javax.swing.SwingUtilities; - import javax.swing.UIManager; public class RenderBadPictureCrash { @@ -41,7 +40,10 @@ public class RenderBadPictureCrash { SwingUtilities.invokeAndWait(() -> { JFrame f = new JFrame(); f.setUndecorated(true); - f.setBackground(new Color(0, 0, 0, 0)); + GraphicsDevice gd = f.getGraphicsConfiguration().getDevice(); + if (gd.isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT)) { + f.setBackground(new Color(0, 0, 0, 0)); + } f.setSize(200, 300); f.setVisible(true); From 3e6267d50c014c46c420b7dbd9828f228810e90d Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 11 Feb 2016 13:42:53 -0800 Subject: [PATCH 006/183] 8149593: Change foo to {@code foo} in TIFF plugin classes Change foo to {@code foo} in TIFF plugin classes and 2015 to 2016 where needed. Reviewed-by: prr, darcy --- .../plugins/tiff/TIFFBaseJPEGCompressor.java | 22 +- .../plugins/tiff/TIFFColorConverter.java | 24 +- .../imageio/plugins/tiff/TIFFCompressor.java | 64 +-- .../plugins/tiff/TIFFDecompressor.java | 504 +++++++++--------- .../plugins/tiff/TIFFExifJPEGCompressor.java | 4 +- .../plugins/tiff/TIFFFaxCompressor.java | 10 +- .../imageio/plugins/tiff/TIFFFieldNode.java | 2 +- .../com/sun/imageio/plugins/tiff/TIFFIFD.java | 10 +- .../plugins/tiff/TIFFImageMetadata.java | 6 +- .../imageio/plugins/tiff/TIFFImageReader.java | 4 +- .../plugins/tiff/TIFFImageWriteParam.java | 18 +- .../imageio/plugins/tiff/TIFFImageWriter.java | 52 +- .../plugins/tiff/TIFFJPEGCompressor.java | 6 +- .../plugins/tiff/TIFFLZWDecompressor.java | 4 +- .../sun/imageio/plugins/tiff/TIFFLZWUtil.java | 4 +- .../plugins/tiff/TIFFNullDecompressor.java | 10 +- .../plugins/tiff/TIFFOldJPEGDecompressor.java | 4 +- .../plugins/tiff/TIFFRLECompressor.java | 6 +- .../plugins/tiff/TIFFRenderedImage.java | 14 +- .../plugins/tiff/TIFFT4Compressor.java | 8 +- .../plugins/tiff/TIFFT6Compressor.java | 4 +- .../plugins/tiff/BaselineTIFFTagSet.java | 6 +- .../imageio/plugins/tiff/ExifGPSTagSet.java | 8 +- .../tiff/ExifInteroperabilityTagSet.java | 6 +- .../plugins/tiff/ExifParentTIFFTagSet.java | 6 +- .../imageio/plugins/tiff/ExifTIFFTagSet.java | 12 +- .../imageio/plugins/tiff/FaxTIFFTagSet.java | 6 +- .../imageio/plugins/tiff/GeoTIFFTagSet.java | 8 +- .../imageio/plugins/tiff/TIFFDirectory.java | 118 ++-- .../javax/imageio/plugins/tiff/TIFFField.java | 368 ++++++------- .../plugins/tiff/TIFFImageReadParam.java | 44 +- .../javax/imageio/plugins/tiff/TIFFTag.java | 84 +-- .../imageio/plugins/tiff/TIFFTagSet.java | 40 +- 33 files changed, 743 insertions(+), 743 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java index 5bb49a5bef7..46185618913 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -86,16 +86,16 @@ public abstract class TIFFBaseJPEGCompressor extends TIFFCompressor { /** * Whether to write abbreviated JPEG streams (default == false). - * A subclass which sets this to true should also + * A subclass which sets this to {@code true} should also * initialized {@link #JPEGStreamMetadata}. */ protected boolean writeAbbreviatedStream = false; /** * Stream metadata equivalent to a tables-only stream such as in - * the JPEGTables. Default value is null. + * the {@code JPEGTables}. Default value is {@code null}. * This should be set by any subclass which sets - * {@link writeAbbreviatedStream} to true. + * {@link writeAbbreviatedStream} to {@code true}. */ protected IIOMetadata JPEGStreamMetadata = null; @@ -108,15 +108,15 @@ public abstract class TIFFBaseJPEGCompressor extends TIFFCompressor { /** * Removes nonessential nodes from a JPEG native image metadata tree. * All nodes derived from JPEG marker segments other than DHT, DQT, - * SOF, SOS segments are removed unless pruneTables is - * true in which case the nodes derived from the DHT and + * SOF, SOS segments are removed unless {@code pruneTables} is + * {@code true} in which case the nodes derived from the DHT and * DQT marker segments are also removed. * * @param tree A javax_imageio_jpeg_image_1.0 tree. * @param pruneTables Whether to prune Huffman and quantization tables. - * @throws NullPointerException if tree is - * null. - * @throws IllegalArgumentException if tree is not the root + * @throws NullPointerException if {@code tree} is + * {@code null}. + * @throws IllegalArgumentException if {@code tree} is not the root * of a JPEG native image metadata tree. */ private static void pruneNodes(Node tree, boolean pruneTables) { @@ -182,8 +182,8 @@ public abstract class TIFFBaseJPEGCompressor extends TIFFCompressor { } /** - * A ByteArrayOutputStream which allows writing to an - * ImageOutputStream. + * A {@code ByteArrayOutputStream} which allows writing to an + * {@code ImageOutputStream}. */ private static class IIOByteArrayOutputStream extends ByteArrayOutputStream { IIOByteArrayOutputStream() { diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFColorConverter.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFColorConverter.java index 3138974ad00..14aa2540acb 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFColorConverter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFColorConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,39 +31,39 @@ package com.sun.imageio.plugins.tiff; public abstract class TIFFColorConverter { /** - * Constructs an instance of a TIFFColorConverter. + * Constructs an instance of a {@code TIFFColorConverter}. */ public TIFFColorConverter() {} /** * Converts an RGB triple into the native color space of this * TIFFColorConverter, and stores the result in the first three - * entries of the result array. + * entries of the {@code result} array. * * @param r the red value. * @param g the green value. * @param b the blue value. - * @param result an array of floats containing three elements. - * @throws NullPointerException if result is - * null. + * @param result an array of {@code float}s containing three elements. + * @throws NullPointerException if {@code result} is + * {@code null}. * @throws ArrayIndexOutOfBoundsException if - * result.length < 3. + * {@code result.length < 3}. */ public abstract void fromRGB(float r, float g, float b, float[] result); /** * Converts a triple in the native color space of this * TIFFColorConverter into an RGB triple, and stores the result in - * the first three entries of the rgb array. + * the first three entries of the {@code rgb} array. * * @param x0 the value of channel 0. * @param x1 the value of channel 1. * @param x2 the value of channel 2. - * @param rgb an array of floats containing three elements. - * @throws NullPointerException if rgb is - * null. + * @param rgb an array of {@code float}s containing three elements. + * @throws NullPointerException if {@code rgb} is + * {@code null}. * @throws ArrayIndexOutOfBoundsException if - * rgb.length < 3. + * {@code rgb.length < 3}. */ public abstract void toRGB(float x0, float x1, float x2, float[] rgb); } diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCompressor.java index cc72f85cea8..ce1b2a58fa1 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,13 +35,13 @@ import javax.imageio.stream.ImageOutputStream; public abstract class TIFFCompressor { /** - * The ImageWriter calling this - * TIFFCompressor. + * The {@code ImageWriter} calling this + * {@code TIFFCompressor}. */ protected ImageWriter writer; /** - * The IIOMetadata object containing metadata for the + * The {@code IIOMetadata} object containing metadata for the * current image. */ protected IIOMetadata metadata; @@ -63,7 +63,7 @@ public abstract class TIFFCompressor { protected boolean isCompressionLossless; /** - * The ImageOutputStream to be written. + * The {@code ImageOutputStream} to be written. */ protected ImageOutputStream stream; @@ -75,26 +75,26 @@ public abstract class TIFFCompressor { * to provide the implementation of the compression algorithm of an * unsupported compression type. * - *

The parameters compressionTagValue and - * isCompressionLossless are provided to accomodate + *

The parameters {@code compressionTagValue} and + * {@code isCompressionLossless} are provided to accomodate * compression types which are unknown. A compression type is * "known" if it is either among those already supported by the * TIFF writer (see {@link TIFFImageWriteParam}), or is listed in * the TIFF 6.0 specification but not supported. If the compression - * type is unknown, the compressionTagValue and - * isCompressionLossless parameters are ignored.

+ * type is unknown, the {@code compressionTagValue} and + * {@code isCompressionLossless} parameters are ignored.

* * @param compressionType The name of the compression type. * @param compressionTagValue The value to be assigned to the TIFF * Compression tag in the TIFF image metadata; ignored if - * compressionType is a known type. + * {@code compressionType} is a known type. * @param isCompressionLossless Whether the compression is lossless; - * ignored if compressionType is a known type. + * ignored if {@code compressionType} is a known type. * - * @throws NullPointerException if compressionType is - * null. - * @throws IllegalArgumentException if compressionTagValue is - * less 1. + * @throws NullPointerException if {@code compressionType} is + * {@code null}. + * @throws IllegalArgumentException if {@code compressionTagValue} is + * less {@code 1}. */ public TIFFCompressor(String compressionType, int compressionTagValue, @@ -163,9 +163,9 @@ public abstract class TIFFCompressor { } /** - * Sets the ImageOutputStream to be written. + * Sets the {@code ImageOutputStream} to be written. * - * @param stream an ImageOutputStream to be written. + * @param stream an {@code ImageOutputStream} to be written. * * @see #getStream */ @@ -174,9 +174,9 @@ public abstract class TIFFCompressor { } /** - * Returns the ImageOutputStream that will be written. + * Returns the {@code ImageOutputStream} that will be written. * - * @return an ImageOutputStream. + * @return an {@code ImageOutputStream}. * * @see #setStream(ImageOutputStream) */ @@ -185,9 +185,9 @@ public abstract class TIFFCompressor { } /** - * Sets the value of the writer field. + * Sets the value of the {@code writer} field. * - * @param writer the current ImageWriter. + * @param writer the current {@code ImageWriter}. * * @see #getWriter() */ @@ -196,9 +196,9 @@ public abstract class TIFFCompressor { } /** - * Returns the current ImageWriter. + * Returns the current {@code ImageWriter}. * - * @return an ImageWriter. + * @return an {@code ImageWriter}. * * @see #setWriter(ImageWriter) */ @@ -207,9 +207,9 @@ public abstract class TIFFCompressor { } /** - * Sets the value of the metadata field. + * Sets the value of the {@code metadata} field. * - * @param metadata the IIOMetadata object for the + * @param metadata the {@code IIOMetadata} object for the * image being written. * * @see #getMetadata() @@ -219,9 +219,9 @@ public abstract class TIFFCompressor { } /** - * Returns the current IIOMetadata object. + * Returns the current {@code IIOMetadata} object. * - * @return the IIOMetadata object for the image being + * @return the {@code IIOMetadata} object for the image being * written. * * @see #setMetadata(IIOMetadata) @@ -232,15 +232,15 @@ public abstract class TIFFCompressor { /** * Encodes the supplied image data, writing to the currently set - * ImageOutputStream. + * {@code ImageOutputStream}. * - * @param b an array of bytes containing the packed + * @param b an array of {@code byte}s containing the packed * but uncompressed image data. * @param off the starting offset of the data to be written in the - * array b. + * array {@code b}. * @param width the width of the rectangle of pixels to be written. * @param height the height of the rectangle of pixels to be written. - * @param bitsPerSample an array of ints indicting + * @param bitsPerSample an array of {@code int}s indicting * the number of bits used to represent each image sample within * a pixel. * @param scanlineStride the number of bytes separating each @@ -249,7 +249,7 @@ public abstract class TIFFCompressor { * @return the number of bytes written. * * @throws IOException if the supplied data cannot be encoded by - * this TIFFCompressor, or if any I/O error occurs + * this {@code TIFFCompressor}, or if any I/O error occurs * during writing. */ public abstract int encode(byte[] b, int off, diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java index fdc29f26016..bdd31218e03 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -81,7 +81,7 @@ import com.sun.imageio.plugins.common.SimpleCMYKColorSpace; * *

Decompressors may be written with various levels of complexity. * The most complex decompressors will override the - * decode method, and will perform all the work of + * {@code decode} method, and will perform all the work of * decoding, subsampling, offsetting, clipping, and format conversion. * This approach may be the most efficient, since it is possible to * avoid the use of extra image buffers, and it may be possible to @@ -89,35 +89,35 @@ import com.sun.imageio.plugins.common.SimpleCMYKColorSpace; * the destination. * *

Less ambitious decompressors may override the - * decodeRaw method, which is responsible for + * {@code decodeRaw} method, which is responsible for * decompressing the entire tile or strip into a byte array (or other * appropriate datatype). The default implementation of - * decode will perform all necessary setup of buffers, - * call decodeRaw to perform the actual decoding, perform + * {@code decode} will perform all necessary setup of buffers, + * call {@code decodeRaw} to perform the actual decoding, perform * subsampling, and copy the results into the final destination image. * Where possible, it will pass the real image buffer to - * decodeRaw in order to avoid making an extra copy. + * {@code decodeRaw} in order to avoid making an extra copy. * *

Slightly more ambitious decompressors may override - * decodeRaw, but avoid writing pixels that will be + * {@code decodeRaw}, but avoid writing pixels that will be * discarded in the subsampling phase. */ public abstract class TIFFDecompressor { /** - * The ImageReader calling this - * TIFFDecompressor. + * The {@code ImageReader} calling this + * {@code TIFFDecompressor}. */ protected ImageReader reader; /** - * The IIOMetadata object containing metadata for the + * The {@code IIOMetadata} object containing metadata for the * current image. */ protected IIOMetadata metadata; /** - * The value of the PhotometricInterpretation tag. + * The value of the {@code PhotometricInterpretation} tag. * Legal values are {@link * BaselineTIFFTagSet#PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO }, * {@link @@ -135,7 +135,7 @@ public abstract class TIFFDecompressor { protected int photometricInterpretation; /** - * The value of the Compression tag. Legal values are + * The value of the {@code Compression} tag. Legal values are * {@link BaselineTIFFTagSet#COMPRESSION_NONE}, {@link * BaselineTIFFTagSet#COMPRESSION_CCITT_RLE}, {@link * BaselineTIFFTagSet#COMPRESSION_CCITT_T_4}, {@link @@ -151,23 +151,23 @@ public abstract class TIFFDecompressor { protected int compression; /** - * true if the image is encoded using separate planes. + * {@code true} if the image is encoded using separate planes. */ protected boolean planar; /** - * The value of the SamplesPerPixel tag. + * The value of the {@code SamplesPerPixel} tag. */ protected int samplesPerPixel; /** - * The value of the BitsPerSample tag. + * The value of the {@code BitsPerSample} tag. * */ protected int[] bitsPerSample; /** - * The value of the SampleFormat tag. Legal values + * The value of the {@code SampleFormat} tag. Legal values * are {@link BaselineTIFFTagSet#SAMPLE_FORMAT_UNSIGNED_INTEGER}, * {@link BaselineTIFFTagSet#SAMPLE_FORMAT_SIGNED_INTEGER}, {@link * BaselineTIFFTagSet#SAMPLE_FORMAT_FLOATING_POINT}, {@link @@ -178,7 +178,7 @@ public abstract class TIFFDecompressor { new int[] {BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER}; /** - * The value of the ExtraSamples tag. Legal values + * The value of the {@code ExtraSamples} tag. Legal values * are {@link BaselineTIFFTagSet#EXTRA_SAMPLES_UNSPECIFIED}, * {@link BaselineTIFFTagSet#EXTRA_SAMPLES_ASSOCIATED_ALPHA}, * {@link BaselineTIFFTagSet#EXTRA_SAMPLES_UNASSOCIATED_ALPHA}, @@ -187,7 +187,7 @@ public abstract class TIFFDecompressor { protected int[] extraSamples; /** - * The value of the ColorMap tag. + * The value of the {@code ColorMap} tag. * */ protected char[] colorMap; @@ -195,20 +195,20 @@ public abstract class TIFFDecompressor { // Region of input stream containing the data /** - * The ImageInputStream containing the TIFF source + * The {@code ImageInputStream} containing the TIFF source * data. */ protected ImageInputStream stream; /** - * The offset in the source ImageInputStream of the + * The offset in the source {@code ImageInputStream} of the * start of the data to be decompressed. */ protected long offset; /** * The number of bytes of data from the source - * ImageInputStream to be decompressed. + * {@code ImageInputStream} to be decompressed. */ protected int byteCount; @@ -244,15 +244,15 @@ public abstract class TIFFDecompressor { // Subsampling to be performed /** - * The source X offset used, along with dstXOffset - * and subsampleX, to map between horizontal source + * The source X offset used, along with {@code dstXOffset} + * and {@code subsampleX}, to map between horizontal source * and destination pixel coordinates. */ protected int sourceXOffset; /** * The horizontal destination offset used, along with - * sourceXOffset and subsampleX, to map + * {@code sourceXOffset} and {@code subsampleX}, to map * between horizontal source and destination pixel coordinates. * See the comment for {@link #sourceXOffset sourceXOffset} for * the mapping equations. @@ -260,15 +260,15 @@ public abstract class TIFFDecompressor { protected int dstXOffset; /** - * The source Y offset used, along with dstYOffset - * and subsampleY, to map between vertical source and + * The source Y offset used, along with {@code dstYOffset} + * and {@code subsampleY}, to map between vertical source and * destination pixel coordinates. */ protected int sourceYOffset; /** * The vertical destination offset used, along with - * sourceYOffset and subsampleY, to map + * {@code sourceYOffset} and {@code subsampleY}, to map * between horizontal source and destination pixel coordinates. * See the comment for {@link #sourceYOffset sourceYOffset} for * the mapping equations. @@ -305,7 +305,7 @@ public abstract class TIFFDecompressor { // Destination for decodeRaw /** - * A BufferedImage for the decodeRaw + * A {@code BufferedImage} for the {@code decodeRaw} * method to write into. */ protected BufferedImage rawImage; @@ -345,15 +345,15 @@ public abstract class TIFFDecompressor { * The X coordinate of the upper-left source pixel that will * actually be copied into the destination image, taking into * account all subsampling, offsetting, and clipping. That is, - * the pixel at (activeSrcMinX, - * activeSrcMinY) is to be copied into the - * destination pixel at (dstMinX, - * dstMinY). + * the pixel at ({@code activeSrcMinX}, + * {@code activeSrcMinY}) is to be copied into the + * destination pixel at ({@code dstMinX}, + * {@code dstMinY}). * *

The pixels in the source region to be copied are - * those with X coordinates of the form activeSrcMinX + - * k*subsampleX, where k is an integer such - * that 0 ≤ k < dstWidth. + * those with X coordinates of the form {@code activeSrcMinX + + * k*subsampleX}, where {@code k} is an integer such + * that {@code 0 ≤ k < dstWidth}. */ protected int activeSrcMinX; @@ -363,9 +363,9 @@ public abstract class TIFFDecompressor { * all subsampling, offsetting, and clipping. * *

The pixels in the source region to be copied are - * those with Y coordinates of the form activeSrcMinY + - * k*subsampleY, where k is an integer such - * that 0 ≤ k < dstHeight. + * those with Y coordinates of the form {@code activeSrcMinY + + * k*subsampleY}, where {@code k} is an integer such + * that {@code 0 ≤ k < dstHeight}. */ protected int activeSrcMinY; @@ -375,7 +375,7 @@ public abstract class TIFFDecompressor { * susbampling, offsetting, and clipping. * *

The active source width will always be equal to - * (dstWidth - 1)*subsampleX + 1. + * {@code (dstWidth - 1)*subsampleX + 1}. */ protected int activeSrcWidth; @@ -385,13 +385,13 @@ public abstract class TIFFDecompressor { * susbampling, offsetting, and clipping. * *

The active source height will always be equal to - * (dstHeight - 1)*subsampleY + 1. + * {@code (dstHeight - 1)*subsampleY + 1}. */ protected int activeSrcHeight; /** - * A TIFFColorConverter object describing the color space of - * the encoded pixel data, or null. + * A {@code TIFFColorConverter} object describing the color space of + * the encoded pixel data, or {@code null}. */ protected TIFFColorConverter colorConverter; @@ -420,13 +420,13 @@ public abstract class TIFFDecompressor { // to exactly those dest pixels that are present in the source region. /** - * Create a PixelInterleavedSampleModel for use in creating - * an ImageTypeSpecifier. Its dimensions will be 1x1 and + * Create a {@code PixelInterleavedSampleModel} for use in creating + * an {@code ImageTypeSpecifier}. Its dimensions will be 1x1 and * it will have ascending band offsets as {0, 1, 2, ..., numBands}. * * @param dataType The data type (DataBuffer.TYPE_*). * @param numBands The number of bands. - * @return A PixelInterleavedSampleModel. + * @return A {@code PixelInterleavedSampleModel}. */ static SampleModel createInterleavedSM(int dataType, int numBands) { @@ -443,8 +443,8 @@ public abstract class TIFFDecompressor { } /** - * Create a ComponentColorModel for use in creating - * an ImageTypeSpecifier. + * Create a {@code ComponentColorModel} for use in creating + * an {@code ImageTypeSpecifier}. */ // This code was copied from javax.imageio.ImageTypeSpecifier. static ColorModel createComponentCM(ColorSpace colorSpace, @@ -518,8 +518,8 @@ public abstract class TIFFDecompressor { } /** - * Return the number of bits occupied by dataType - * which must be one of the DataBuffer TYPEs. + * Return the number of bits occupied by {@code dataType} + * which must be one of the {@code DataBuffer} {@code TYPE}s. */ private static int getDataTypeSize(int dataType) throws IIOException { int dataTypeSize = 0; @@ -578,7 +578,7 @@ public abstract class TIFFDecompressor { } /** - * Determines whether the DataBuffer is filled without + * Determines whether the {@code DataBuffer} is filled without * any interspersed padding bits. */ private static boolean isDataBufferBitContiguous(SampleModel sm) @@ -678,8 +678,8 @@ public abstract class TIFFDecompressor { } /** - * Reformats bit-discontiguous data into the DataBuffer - * of the supplied WritableRaster. + * Reformats bit-discontiguous data into the {@code DataBuffer} + * of the supplied {@code WritableRaster}. */ private static void reformatDiscontiguousData(byte[] buf, int stride, @@ -715,21 +715,21 @@ public abstract class TIFFDecompressor { /** * A utility method that returns an - * ImageTypeSpecifier suitable for decoding an image + * {@code ImageTypeSpecifier} suitable for decoding an image * with the given parameters. * * @param photometricInterpretation the value of the - * PhotometricInterpretation field. - * @param compression the value of the Compression field. + * {@code PhotometricInterpretation} field. + * @param compression the value of the {@code Compression} field. * @param samplesPerPixel the value of the - * SamplesPerPixel field. - * @param bitsPerSample the value of the BitsPerSample field. - * @param sampleFormat the value of the SampleFormat field. - * @param extraSamples the value of the ExtraSamples field. - * @param colorMap the value of the ColorMap field. + * {@code SamplesPerPixel} field. + * @param bitsPerSample the value of the {@code BitsPerSample} field. + * @param sampleFormat the value of the {@code SampleFormat} field. + * @param extraSamples the value of the {@code ExtraSamples} field. + * @param colorMap the value of the {@code ColorMap} field. * - * @return a suitable ImageTypeSpecifier, or - * null if it is not possible to create one. + * @return a suitable {@code ImageTypeSpecifier}, or + * {@code null} if it is not possible to create one. */ public static ImageTypeSpecifier getRawImageTypeSpecifier(int photometricInterpretation, @@ -1216,26 +1216,26 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the reader field. + * Sets the value of the {@code reader} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param reader the current ImageReader. + * @param reader the current {@code ImageReader}. */ public void setReader(ImageReader reader) { this.reader = reader; } /** - * Sets the value of the metadata field. + * Sets the value of the {@code metadata} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param metadata the IIOMetadata object for the + * @param metadata the {@code IIOMetadata} object for the * image being read. */ public void setMetadata(IIOMetadata metadata) { @@ -1243,10 +1243,10 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the photometricInterpretation + * Sets the value of the {@code photometricInterpretation} * field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1258,9 +1258,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the compression field. + * Sets the value of the {@code compression} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1271,13 +1271,13 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the planar field. + * Sets the value of the {@code planar} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param planar true if the image to be decoded is + * @param planar {@code true} if the image to be decoded is * stored in planar format. */ public void setPlanar(boolean planar) { @@ -1285,9 +1285,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the samplesPerPixel field. + * Sets the value of the {@code samplesPerPixel} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1299,9 +1299,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the bitsPerSample field. + * Sets the value of the {@code bitsPerSample} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1314,9 +1314,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the sampleFormat field. + * Sets the value of the {@code sampleFormat} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1330,9 +1330,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the extraSamples field. + * Sets the value of the {@code extraSamples} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1346,14 +1346,14 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the colorMap field. + * Sets the value of the {@code colorMap} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * * @param colorMap the color map to apply to the source data, - * as an array of chars. + * as an array of {@code char}s. */ public void setColorMap(char[] colorMap) { this.colorMap = colorMap == null ? @@ -1361,22 +1361,22 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the stream field. + * Sets the value of the {@code stream} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param stream the ImageInputStream to be read. + * @param stream the {@code ImageInputStream} to be read. */ public void setStream(ImageInputStream stream) { this.stream = stream; } /** - * Sets the value of the offset field. + * Sets the value of the {@code offset} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1388,9 +1388,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the byteCount field. + * Sets the value of the {@code byteCount} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1403,9 +1403,9 @@ public abstract class TIFFDecompressor { // Region of the file image represented in the stream /** - * Sets the value of the srcMinX field. + * Sets the value of the {@code srcMinX} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1418,9 +1418,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the srcMinY field. + * Sets the value of the {@code srcMinY} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1433,9 +1433,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the srcWidth field. + * Sets the value of the {@code srcWidth} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1447,9 +1447,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the srcHeight field. + * Sets the value of the {@code srcHeight} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1463,9 +1463,9 @@ public abstract class TIFFDecompressor { // First source pixel to be read /** - * Sets the value of the sourceXOffset field. + * Sets the value of the {@code sourceXOffset} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1477,9 +1477,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the dstXOffset field. + * Sets the value of the {@code dstXOffset} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1491,9 +1491,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the sourceYOffset. + * Sets the value of the {@code sourceYOffset}. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1505,9 +1505,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the dstYOffset field. + * Sets the value of the {@code dstYOffset} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1521,15 +1521,15 @@ public abstract class TIFFDecompressor { // Subsampling to be performed /** - * Sets the value of the subsampleX field. + * Sets the value of the {@code subsampleX} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * * @param subsampleX the horizontal subsampling factor. * - * @throws IllegalArgumentException if subsampleX is + * @throws IllegalArgumentException if {@code subsampleX} is * less than or equal to 0. */ public void setSubsampleX(int subsampleX) { @@ -1540,15 +1540,15 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the subsampleY field. + * Sets the value of the {@code subsampleY} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * * @param subsampleY the vertical subsampling factor. * - * @throws IllegalArgumentException if subsampleY is + * @throws IllegalArgumentException if {@code subsampleY} is * less than or equal to 0. */ public void setSubsampleY(int subsampleY) { @@ -1561,13 +1561,13 @@ public abstract class TIFFDecompressor { // Band subsetting/rearrangement /** - * Sets the value of the sourceBands field. + * Sets the value of the {@code sourceBands} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param sourceBands an array of ints + * @param sourceBands an array of {@code int}s * specifying the source bands to be read. */ public void setSourceBands(int[] sourceBands) { @@ -1576,13 +1576,13 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the destinationBands field. + * Sets the value of the {@code destinationBands} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param destinationBands an array of ints + * @param destinationBands an array of {@code int}s * specifying the destination bands to be written. */ public void setDestinationBands(int[] destinationBands) { @@ -1593,22 +1593,22 @@ public abstract class TIFFDecompressor { // Destination image and region /** - * Sets the value of the image field. + * Sets the value of the {@code image} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param image the destination BufferedImage. + * @param image the destination {@code BufferedImage}. */ public void setImage(BufferedImage image) { this.image = image; } /** - * Sets the value of the dstMinX field. + * Sets the value of the {@code dstMinX} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1620,9 +1620,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the dstMinY field. + * Sets the value of the {@code dstMinY} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1634,9 +1634,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the dstWidth field. + * Sets the value of the {@code dstWidth} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1647,9 +1647,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the dstHeight field. + * Sets the value of the {@code dstHeight} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1662,9 +1662,9 @@ public abstract class TIFFDecompressor { // Active source region /** - * Sets the value of the activeSrcMinX field. + * Sets the value of the {@code activeSrcMinX} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1676,9 +1676,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the activeSrcMinY field. + * Sets the value of the {@code activeSrcMinY} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1690,9 +1690,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the activeSrcWidth field. + * Sets the value of the {@code activeSrcWidth} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1703,9 +1703,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the activeSrcHeight field. + * Sets the value of the {@code activeSrcHeight} field. * - *

If this method is called, the beginDecoding + *

If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1716,23 +1716,23 @@ public abstract class TIFFDecompressor { } /** - * Sets the TIFFColorConverter object describing the color + * Sets the {@code TIFFColorConverter} object describing the color * space of the encoded data in the input stream. If no - * TIFFColorConverter is set, no conversion will be performed. + * {@code TIFFColorConverter} is set, no conversion will be performed. * - * @param colorConverter a TIFFColorConverter object, or - * null. + * @param colorConverter a {@code TIFFColorConverter} object, or + * {@code null}. */ public void setColorConverter(TIFFColorConverter colorConverter) { this.colorConverter = colorConverter; } /** - * Returns an ImageTypeSpecifier describing an image + * Returns an {@code ImageTypeSpecifier} describing an image * whose underlying data array has the same format as the raw * source pixel data. * - * @return an ImageTypeSpecifier. + * @return an {@code ImageTypeSpecifier}. */ public ImageTypeSpecifier getRawImageType() { ImageTypeSpecifier its = @@ -1747,18 +1747,18 @@ public abstract class TIFFDecompressor { } /** - * Creates a BufferedImage whose underlying data + * Creates a {@code BufferedImage} whose underlying data * array will be suitable for holding the raw decoded output of - * the decodeRaw method. + * the {@code decodeRaw} method. * *

The default implementation calls - * getRawImageType, and calls the resulting - * ImageTypeSpecifier's - * createBufferedImage method. + * {@code getRawImageType}, and calls the resulting + * {@code ImageTypeSpecifier}'s + * {@code createBufferedImage} method. * - * @return a BufferedImage whose underlying data + * @return a {@code BufferedImage} whose underlying data * array has the same format as the raw source pixel data, or - * null if it is not possible to create such an + * {@code null} if it is not possible to create such an * image. */ public BufferedImage createRawImage() { @@ -1811,22 +1811,22 @@ public abstract class TIFFDecompressor { } /** - * Decodes the source data into the provided byte - * array b, starting at the offset given by - * dstOffset. Each pixel occupies - * bitsPerPixel bits, with no padding between pixels. - * Scanlines are separated by scanlineStride - * bytes. + * Decodes the source data into the provided {@code byte} + * array {@code b}, starting at the offset given by + * {@code dstOffset}. Each pixel occupies + * {@code bitsPerPixel} bits, with no padding between pixels. + * Scanlines are separated by {@code scanlineStride} + * {@code byte}s. * - * @param b a byte array to be written. - * @param dstOffset the starting offset in b to be + * @param b a {@code byte} array to be written. + * @param dstOffset the starting offset in {@code b} to be * written. * @param bitsPerPixel the number of bits for each pixel. - * @param scanlineStride the number of bytes to + * @param scanlineStride the number of {@code byte}s to * advance between that starting pixels of each scanline. * * @throws IOException if an error occurs reading from the source - * ImageInputStream. + * {@code ImageInputStream}. */ public abstract void decodeRaw(byte[] b, int dstOffset, @@ -1834,25 +1834,25 @@ public abstract class TIFFDecompressor { int scanlineStride) throws IOException; /** - * Decodes the source data into the provided short - * array s, starting at the offset given by - * dstOffset. Each pixel occupies - * bitsPerPixel bits, with no padding between pixels. - * Scanlines are separated by scanlineStride - * shorts + * Decodes the source data into the provided {@code short} + * array {@code s}, starting at the offset given by + * {@code dstOffset}. Each pixel occupies + * {@code bitsPerPixel} bits, with no padding between pixels. + * Scanlines are separated by {@code scanlineStride} + * {@code short}s * - *

The default implementation calls decodeRaw(byte[] b, - * ...) and copies the resulting data into s. + *

The default implementation calls {@code decodeRaw(byte[] b, + * ...)} and copies the resulting data into {@code s}. * - * @param s a short array to be written. - * @param dstOffset the starting offset in s to be + * @param s a {@code short} array to be written. + * @param dstOffset the starting offset in {@code s} to be * written. * @param bitsPerPixel the number of bits for each pixel. - * @param scanlineStride the number of shorts to + * @param scanlineStride the number of {@code short}s to * advance between that starting pixels of each scanline. * * @throws IOException if an error occurs reading from the source - * ImageInputStream. + * {@code ImageInputStream}. */ public void decodeRaw(short[] s, int dstOffset, @@ -1891,25 +1891,25 @@ public abstract class TIFFDecompressor { } /** - * Decodes the source data into the provided int - * array i, starting at the offset given by - * dstOffset. Each pixel occupies - * bitsPerPixel bits, with no padding between pixels. - * Scanlines are separated by scanlineStride - * ints. + * Decodes the source data into the provided {@code int} + * array {@code i}, starting at the offset given by + * {@code dstOffset}. Each pixel occupies + * {@code bitsPerPixel} bits, with no padding between pixels. + * Scanlines are separated by {@code scanlineStride} + * {@code int}s. * - *

The default implementation calls decodeRaw(byte[] b, - * ...) and copies the resulting data into i. + *

The default implementation calls {@code decodeRaw(byte[] b, + * ...)} and copies the resulting data into {@code i}. * - * @param i an int array to be written. - * @param dstOffset the starting offset in i to be + * @param i an {@code int} array to be written. + * @param dstOffset the starting offset in {@code i} to be * written. * @param bitsPerPixel the number of bits for each pixel. - * @param scanlineStride the number of ints to + * @param scanlineStride the number of {@code int}s to * advance between that starting pixels of each scanline. * * @throws IOException if an error occurs reading from the source - * ImageInputStream. + * {@code ImageInputStream}. */ public void decodeRaw(int[] i, int dstOffset, @@ -1953,25 +1953,25 @@ public abstract class TIFFDecompressor { } /** - * Decodes the source data into the provided float - * array f, starting at the offset given by - * dstOffset. Each pixel occupies - * bitsPerPixel bits, with no padding between pixels. - * Scanlines are separated by scanlineStride - * floats. + * Decodes the source data into the provided {@code float} + * array {@code f}, starting at the offset given by + * {@code dstOffset}. Each pixel occupies + * {@code bitsPerPixel} bits, with no padding between pixels. + * Scanlines are separated by {@code scanlineStride} + * {@code float}s. * - *

The default implementation calls decodeRaw(byte[] b, - * ...) and copies the resulting data into f. + *

The default implementation calls {@code decodeRaw(byte[] b, + * ...)} and copies the resulting data into {@code f}. * - * @param f a float array to be written. - * @param dstOffset the starting offset in f to be + * @param f a {@code float} array to be written. + * @param dstOffset the starting offset in {@code f} to be * written. * @param bitsPerPixel the number of bits for each pixel. - * @param scanlineStride the number of floats to + * @param scanlineStride the number of {@code float}s to * advance between that starting pixels of each scanline. * * @throws IOException if an error occurs reading from the source - * ImageInputStream. + * {@code ImageInputStream}. */ public void decodeRaw(float[] f, int dstOffset, @@ -2017,25 +2017,25 @@ public abstract class TIFFDecompressor { } /** - * Decodes the source data into the provided double - * array f, starting at the offset given by - * dstOffset. Each pixel occupies - * bitsPerPixel bits, with no padding between pixels. - * Scanlines are separated by scanlineStride - * doubles. + * Decodes the source data into the provided {@code double} + * array {@code f}, starting at the offset given by + * {@code dstOffset}. Each pixel occupies + * {@code bitsPerPixel} bits, with no padding between pixels. + * Scanlines are separated by {@code scanlineStride} + * {@code double}s. * - *

The default implementation calls decodeRaw(byte[] b, - * ...) and copies the resulting data into f. + *

The default implementation calls {@code decodeRaw(byte[] b, + * ...)} and copies the resulting data into {@code f}. * - * @param f a double array to be written. - * @param dstOffset the starting offset in f to be + * @param f a {@code double} array to be written. + * @param dstOffset the starting offset in {@code f} to be * written. * @param bitsPerPixel the number of bits for each pixel. - * @param scanlineStride the number of doubles to + * @param scanlineStride the number of {@code double}s to * advance between that starting pixels of each scanline. * * @throws IOException if an error occurs reading from the source - * ImageInputStream. + * {@code ImageInputStream}. */ public void decodeRaw(double[] d, int dstOffset, @@ -2104,16 +2104,16 @@ public abstract class TIFFDecompressor { /** * This routine is called prior to a sequence of calls to the - * decode method, in order to allow any necessary + * {@code decode} method, in order to allow any necessary * tables or other structures to be initialized based on metadata * values. This routine is guaranteed to be called any time the * metadata values have changed. * *

The default implementation computes tables used by the - * decode method to rescale components to different + * {@code decode} method to rescale components to different * bit depths. Thus, if this method is overridden, it is - * important for the subclass method to call super(), - * unless it overrides decode as well. + * important for the subclass method to call {@code super()}, + * unless it overrides {@code decode} as well. */ public void beginDecoding() { // Note: This method assumes that sourceBands, destinationBands, @@ -2242,35 +2242,35 @@ public abstract class TIFFDecompressor { /** * Decodes the input bit stream (located in the - * ImageInputStream stream, at offset - * offset, and continuing for byteCount - * bytes) into the output BufferedImage - * image. + * {@code ImageInputStream} {@code stream}, at offset + * {@code offset}, and continuing for {@code byteCount} + * bytes) into the output {@code BufferedImage} + * {@code image}. * *

The default implementation analyzes the destination image * to determine if it is suitable as the destination for the - * decodeRaw method. If not, a suitable image is - * created. Next, decodeRaw is called to perform the + * {@code decodeRaw} method. If not, a suitable image is + * created. Next, {@code decodeRaw} is called to perform the * actual decoding, and the results are copied into the * destination image if necessary. Subsampling and offsetting are * performed automatically. * *

The precise responsibilities of this routine are as * follows. The input bit stream is defined by the instance - * variables stream, offset, and - * byteCount. These bits contain the data for the - * region of the source image defined by srcMinX, - * srcMinY, srcWidth, and - * srcHeight. + * variables {@code stream}, {@code offset}, and + * {@code byteCount}. These bits contain the data for the + * region of the source image defined by {@code srcMinX}, + * {@code srcMinY}, {@code srcWidth}, and + * {@code srcHeight}. * *

The source data is required to be subsampling, starting at - * the sourceXOffsetth column and including - * every subsampleXth pixel thereafter (and similarly - * for sourceYOffset and - * subsampleY). + * the {@code sourceXOffset}th column and including + * every {@code subsampleX}th pixel thereafter (and similarly + * for {@code sourceYOffset} and + * {@code subsampleY}). * *

Pixels are copied into the destination with an addition shift of - * (dstXOffset, dstYOffset). The complete + * ({@code dstXOffset}, {@code dstYOffset}). The complete * set of formulas relating the source and destination coordinate spaces * are: * @@ -2279,9 +2279,9 @@ public abstract class TIFFDecompressor { * dy = (sy - sourceYOffset)/subsampleY + dstYOffset; * * - * Only source pixels such that (sx - sourceXOffset) % - * subsampleX == 0 and (sy - sourceYOffset) % - * subsampleY == 0 are copied. + * Only source pixels such that {@code (sx - sourceXOffset) % + * subsampleX == 0} and {@code (sy - sourceYOffset) % + * subsampleY == 0} are copied. * *

The inverse mapping, from destination to source coordinates, * is one-to-one: @@ -2292,9 +2292,9 @@ public abstract class TIFFDecompressor { * * *

The region of the destination image to be updated is given - * by the instance variables dstMinX, - * dstMinY, dstWidth, and - * dstHeight. + * by the instance variables {@code dstMinX}, + * {@code dstMinY}, {@code dstWidth}, and + * {@code dstHeight}. * *

It is possible that not all of the source data being read * will contribute to the destination image. For example, the @@ -2303,32 +2303,32 @@ public abstract class TIFFDecompressor { * convenience, the bounds of the active source region (that is, * the region of the strip or tile being read that actually * contributes to the destination image, taking clipping into - * account) are available as activeSrcMinX, - * activeSrcMinY, activeSrcWidth and - * activeSrcHeight. Thus, the source pixel at - * (activeSrcMinX, activeSrcMinY) will - * map to the destination pixel (dstMinX, - * dstMinY). + * account) are available as {@code activeSrcMinX}, + * {@code activeSrcMinY}, {@code activeSrcWidth} and + * {@code activeSrcHeight}. Thus, the source pixel at + * ({@code activeSrcMinX}, {@code activeSrcMinY}) will + * map to the destination pixel ({@code dstMinX}, + * {@code dstMinY}). * *

The sequence of source bands given by - * sourceBands are to be copied into the sequence of + * {@code sourceBands} are to be copied into the sequence of * bands in the destination given by - * destinationBands. + * {@code destinationBands}. * *

Some standard tag information is provided the instance - * variables photometricInterpretation, - * compression, samplesPerPixel, - * bitsPerSample, sampleFormat, - * extraSamples, and colorMap. + * variables {@code photometricInterpretation}, + * {@code compression}, {@code samplesPerPixel}, + * {@code bitsPerSample}, {@code sampleFormat}, + * {@code extraSamples}, and {@code colorMap}. * *

In practice, unless there is a significant performance * advantage to be gained by overriding this routine, most users * will prefer to use the default implementation of this routine, - * and instead override the decodeRaw and/or - * getRawImageType methods. + * and instead override the {@code decodeRaw} and/or + * {@code getRawImageType} methods. * * @exception IOException if an error occurs in - * decodeRaw. + * {@code decodeRaw}. */ public void decode() throws IOException { byte[] byteData = null; diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java index b3e202cb2cd..3541ce110db 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -29,7 +29,7 @@ import javax.imageio.metadata.IIOMetadata; import javax.imageio.plugins.tiff.BaselineTIFFTagSet; /** - * A TIFFCompressor for the JPEG variant of Exif. + * A {@code TIFFCompressor} for the JPEG variant of Exif. */ public class TIFFExifJPEGCompressor extends TIFFBaseJPEGCompressor { public TIFFExifJPEGCompressor(ImageWriteParam param) { diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java index 9cbf49eb84b..5c126acab53 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -232,12 +232,12 @@ abstract class TIFFFaxCompressor extends TIFFCompressor { } /** - * Sets the value of the metadata field. + * Sets the value of the {@code metadata} field. * *

The implementation in this class also sets local options * from the FILL_ORDER field if it exists.

* - * @param metadata the IIOMetadata object for the + * @param metadata the {@code IIOMetadata} object for the * image being written. * * @see #getMetadata() @@ -253,8 +253,8 @@ abstract class TIFFFaxCompressor extends TIFFCompressor { } /** - * Return min of maxOffset or offset of first pixel - * different from pixel at bitOffset. + * Return min of {@code maxOffset} or offset of first pixel + * different from pixel at {@code bitOffset}. */ public int nextState(byte[] data, int base, diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java index e78954b34e4..994d10d7810 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java @@ -34,7 +34,7 @@ import javax.imageio.plugins.tiff.TIFFTag; import javax.imageio.plugins.tiff.TIFFTagSet; /** - * The Node representation of a TIFFField + * The {@code Node} representation of a {@code TIFFField} * wherein the child node is procedural rather than buffered. */ public class TIFFFieldNode extends IIOMetadataNode { diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java index c60a98c793b..46d1419ee4c 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -153,7 +153,7 @@ public class TIFFIFD extends TIFFDirectory { } /** - * Returns an Iterator over the TIFF fields. The + * Returns an {@code Iterator} over the TIFF fields. The * traversal is in the order of increasing tag number. */ // Note: the sort is guaranteed for low fields by the use of an @@ -164,7 +164,7 @@ public class TIFFIFD extends TIFFDirectory { } /** - * Read the value of a field. The data parameter should be + * Read the value of a field. The {@code data} parameter should be * an array of length 1 of Object. * * @param stream the input stream @@ -762,8 +762,8 @@ public class TIFFIFD extends TIFFDirectory { } /** - * Returns a TIFFIFD wherein all fields from the - * BaselineTIFFTagSet are copied by value and all other + * Returns a {@code TIFFIFD} wherein all fields from the + * {@code BaselineTIFFTagSet} are copied by value and all other * fields copied by reference. */ public TIFFIFD getShallowClone() { diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java index decebe16f0c..933c2da5a6c 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -1620,8 +1620,8 @@ public class TIFFImageMetadata extends IIOMetadata { } /** - * Returns a TIFFImageMetadata wherein all fields in the - * root IFD from the BaselineTIFFTagSet are copied by value + * Returns a {@code TIFFImageMetadata} wherein all fields in the + * root IFD from the {@code BaselineTIFFTagSet} are copied by value * and all other fields copied by reference. */ public TIFFImageMetadata getShallowClone() { diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java index 47356e0d6a2..317027351fc 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -83,7 +83,7 @@ public class TIFFImageReader extends ImageReader { // Metadata for image at 'currIndex', or null. private TIFFImageMetadata imageMetadata = null; - // A List of Longs indicating the stream + // A {@code List} of {@code Long}s indicating the stream // positions of the start of the IFD for each image. Entries // are added as needed. private List imageStartPosition = new ArrayList(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriteParam.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriteParam.java index 21dc5cb7eb4..c30f7ec70f9 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriteParam.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriteParam.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -122,11 +122,11 @@ import javax.imageio.ImageWriteParam; * quality value is passed directly to the JPEG writer plug-in which * interprets it in the usual way.

* - *

The canWriteTiles and - * canWriteCompressed methods will return - * true; the canOffsetTiles and - * canWriteProgressive methods will return - * false.

+ *

The {@code canWriteTiles} and + * {@code canWriteCompressed} methods will return + * {@code true}; the {@code canOffsetTiles} and + * {@code canWriteProgressive} methods will return + * {@code false}.

* *

If tiles are being written, then each of their dimensions will be * rounded to the nearest multiple of 16 per the TIFF specification. If @@ -140,10 +140,10 @@ import javax.imageio.ImageWriteParam; public class TIFFImageWriteParam extends ImageWriteParam { /** - * Constructs a TIFFImageWriteParam instance - * for a given Locale. + * Constructs a {@code TIFFImageWriteParam} instance + * for a given {@code Locale}. * - * @param locale the Locale for which messages + * @param locale the {@code Locale} for which messages * should be localized. */ public TIFFImageWriteParam(Locale locale) { diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java index ea819e9e968..d0d5c3e5ce0 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -221,11 +221,11 @@ public class TIFFImageWriter extends ImageWriter { * relative to a given tile grid layout specified by its X offset * and tile width. * - *

If tileWidth < 0, the results of this method - * are undefined. If tileWidth == 0, an - * ArithmeticException will be thrown. + *

If {@code tileWidth < 0}, the results of this method + * are undefined. If {@code tileWidth == 0}, an + * {@code ArithmeticException} will be thrown. * - * @throws ArithmeticException If tileWidth == 0. + * @throws ArithmeticException If {@code tileWidth == 0}. */ public static int XToTileX(int x, int tileGridXOffset, int tileWidth) { x -= tileGridXOffset; @@ -240,11 +240,11 @@ public class TIFFImageWriter extends ImageWriter { * relative to a given tile grid layout specified by its Y offset * and tile height. * - *

If tileHeight < 0, the results of this method - * are undefined. If tileHeight == 0, an - * ArithmeticException will be thrown. + *

If {@code tileHeight < 0}, the results of this method + * are undefined. If {@code tileHeight == 0}, an + * {@code ArithmeticException} will be thrown. * - * @throws ArithmeticException If tileHeight == 0. + * @throws ArithmeticException If {@code tileHeight == 0}. */ public static int YToTileY(int y, int tileGridYOffset, int tileHeight) { y -= tileGridYOffset; @@ -424,17 +424,17 @@ public class TIFFImageWriter extends ImageWriter { } /** - * Converts a standard javax_imageio_1.0 tree to a - * TIFFImageMetadata object. + * Converts a standard {@code javax_imageio_1.0} tree to a + * {@code TIFFImageMetadata} object. * * @param inData The metadata object. - * @return a TIFFImageMetadata or null if - * the standard tree derived from the input object is null. - * @throws IllegalArgumentException if inData is - * null. - * @throws IllegalArgumentException if inData does not support + * @return a {@code TIFFImageMetadata} or {@code null} if + * the standard tree derived from the input object is {@code null}. + * @throws IllegalArgumentException if {@code inData} is + * {@code null}. + * @throws IllegalArgumentException if {@code inData} does not support * the standard metadata format. - * @throws IIOInvalidTreeException if inData generates an + * @throws IIOInvalidTreeException if {@code inData} generates an * invalid standard metadata tree. */ private TIFFImageMetadata convertStandardImageMetadata(IIOMetadata inData) @@ -463,15 +463,15 @@ public class TIFFImageWriter extends ImageWriter { /** * Converts a native - * javax_imageio_tiff_image_1.0 tree to a - * TIFFImageMetadata object. + * {@code javax_imageio_tiff_image_1.0} tree to a + * {@code TIFFImageMetadata} object. * * @param inData The metadata object. - * @return a TIFFImageMetadata or null if - * the native tree derived from the input object is null. - * @throws IllegalArgumentException if inData is - * null or does not support the native metadata format. - * @throws IIOInvalidTreeException if inData generates an + * @return a {@code TIFFImageMetadata} or {@code null} if + * the native tree derived from the input object is {@code null}. + * @throws IllegalArgumentException if {@code inData} is + * {@code null} or does not support the native metadata format. + * @throws IIOInvalidTreeException if {@code inData} generates an * invalid native metadata tree. */ private TIFFImageMetadata convertNativeImageMetadata(IIOMetadata inData) @@ -504,8 +504,8 @@ public class TIFFImageWriter extends ImageWriter { * as needed. The destination image dimensions are provided as parameters * because these might differ from those of the source due to subsampling. * - * @param cm The ColorModel of the image being written. - * @param sm The SampleModel of the image being written. + * @param cm The {@code ColorModel} of the image being written. + * @param sm The {@code SampleModel} of the image being written. * @param destWidth The width of the written image after subsampling. * @param destHeight The height of the written image after subsampling. */ diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java index a631a3a926c..7b6cfcf5b28 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -102,14 +102,14 @@ public class TIFFJPEGCompressor extends TIFFBaseJPEGCompressor { } /** - * Sets the value of the metadata field. + * Sets the value of the {@code metadata} field. * *

The implementation in this class also adds the TIFF fields * JPEGTables, YCbCrSubSampling, YCbCrPositioning, and * ReferenceBlackWhite superseding any prior settings of those * fields.

* - * @param metadata the IIOMetadata object for the + * @param metadata the {@code IIOMetadata} object for the * image being written. * * @see #getMetadata() diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java index d53a275955f..cbf3b504f63 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -245,7 +245,7 @@ class TIFFLZWDecompressor extends TIFFDecompressor { } /** - * Append newString to the end of oldString. + * Append {@code newString} to the end of {@code oldString}. */ public byte[] composeString(byte oldString[], byte newString) { int length = oldString.length; diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWUtil.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWUtil.java index 92656697d2c..2a61535cff3 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWUtil.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -188,7 +188,7 @@ class TIFFLZWUtil { } /** - * Append newString to the end of oldString. + * Append {@code newString} to the end of {@code oldString}. */ public byte[] composeString(byte oldString[], byte newString) { int length = oldString.length; diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java index 657bd28861b..6ffc1f0acb7 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -34,16 +34,16 @@ public class TIFFNullDecompressor extends TIFFDecompressor { */ private boolean isReadActiveOnly = false; - /** The original value of srcMinX. */ + /** The original value of {@code srcMinX}. */ private int originalSrcMinX; - /** The original value of srcMinY. */ + /** The original value of {@code srcMinY}. */ private int originalSrcMinY; - /** The original value of srcWidth. */ + /** The original value of {@code srcWidth}. */ private int originalSrcWidth; - /** The original value of srcHeight. */ + /** The original value of {@code srcHeight}. */ private int originalSrcHeight; public TIFFNullDecompressor() {} diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java index 264657ddb2a..2837754ddb2 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -34,7 +34,7 @@ import javax.imageio.plugins.tiff.BaselineTIFFTagSet; import javax.imageio.plugins.tiff.TIFFField; /** - * TIFFDecompressor for "Old JPEG" compression. + * {@code TIFFDecompressor} for "Old JPEG" compression. */ public class TIFFOldJPEGDecompressor extends TIFFJPEGDecompressor { diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java index cebfdfb2221..523f9eaa574 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -42,8 +42,8 @@ public class TIFFRLECompressor extends TIFFFaxCompressor { * CCITT RLE (Run Lenth Encoding). * * @param data The row of data to compress. - * @param rowOffset Starting index in data. - * @param colOffset Bit offset within first data[rowOffset]. + * @param rowOffset Starting index in {@code data}. + * @param colOffset Bit offset within first {@code data[rowOffset]}. * @param rowLength Number of bits in the row. * @param compData The compressed data. * diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java index 98a336f8c8f..77e0c9a109c 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -85,15 +85,15 @@ public class TIFFRenderedImage implements RenderedImage { } /** - * Creates a copy of param. The source subsampling and + * Creates a copy of {@code param}. The source subsampling and * and bands settings and the destination bands and offset settings - * are copied. If param is a TIFFImageReadParam - * then the TIFFDecompressor and - * TIFFColorConverter settings are also copied; otherwise - * they are explicitly set to null. + * are copied. If {@code param} is a {@code TIFFImageReadParam} + * then the {@code TIFFDecompressor} and + * {@code TIFFColorConverter} settings are also copied; otherwise + * they are explicitly set to {@code null}. * * @param param the parameters to be copied. - * @param copyTagSets whether the TIFFTagSet settings + * @param copyTagSets whether the {@code TIFFTagSet} settings * should be copied if set. * @return copied parameters. */ diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java index fa2652ef902..55088e34dfe 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -41,13 +41,13 @@ public class TIFFT4Compressor extends TIFFFaxCompressor { } /** - * Sets the value of the metadata field. + * Sets the value of the {@code metadata} field. * *

The implementation in this class also sets local options * from the T4_OPTIONS field if it exists, and if it doesn't, adds * it with default values.

* - * @param metadata the IIOMetadata object for the + * @param metadata the {@code IIOMetadata} object for the * image being written. * * @see #getMetadata() @@ -86,7 +86,7 @@ public class TIFFT4Compressor extends TIFFFaxCompressor { * @param isEOLAligned Whether EOL bit sequences should be padded. * @param data The row of data to compress. * @param lineStride Byte step between the same sample in different rows. - * @param colOffset Bit offset within first data[rowOffset]. + * @param colOffset Bit offset within first {@code data[rowOffset]}. * @param width Number of bits in the row. * @param height Number of rows in the buffer. * @param compData The compressed data. diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java index 964bba05032..517c23bde54 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -42,7 +42,7 @@ public class TIFFT6Compressor extends TIFFFaxCompressor { * * @param data The row of data to compress. * @param lineStride Byte step between the same sample in different rows. - * @param colOffset Bit offset within first data[rowOffset]. + * @param colOffset Bit offset within first {@code data[rowOffset]}. * @param width Number of bits in the row. * @param height Number of rows in the buffer. * @param compData The compressed data. diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java index d434acf8ab3..d1dbd3cf4fb 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -2175,9 +2175,9 @@ public class BaselineTIFFTagSet extends TIFFTagSet { } /** - * Returns a shared instance of a BaselineTIFFTagSet. + * Returns a shared instance of a {@code BaselineTIFFTagSet}. * - * @return a BaselineTIFFTagSet instance. + * @return a {@code BaselineTIFFTagSet} instance. */ public synchronized static BaselineTIFFTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java index d37a1330d12..03198c45c51 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -51,7 +51,7 @@ public class ExifGPSTagSet extends TIFFTagSet { /** * A value to be used with the "GPSVersionID" tag to indicate GPS version * 2.2. The value equals the US-ASCII encoding of the byte array - * {'2', '2', '0', '0'}. + * {@code {'2', '2', '0', '0'}}. * * @see #TAG_GPS_VERSION_ID */ @@ -711,9 +711,9 @@ public class ExifGPSTagSet extends TIFFTagSet { } /** - * Returns a shared instance of an ExifGPSTagSet. + * Returns a shared instance of an {@code ExifGPSTagSet}. * - * @return an ExifGPSTagSet instance. + * @return an {@code ExifGPSTagSet} instance. */ public synchronized static ExifGPSTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifInteroperabilityTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifInteroperabilityTagSet.java index b2a52790f0b..7089c653fbe 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifInteroperabilityTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifInteroperabilityTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -88,9 +88,9 @@ public class ExifInteroperabilityTagSet extends TIFFTagSet { /** * Returns the shared instance of - * ExifInteroperabilityTagSet. + * {@code ExifInteroperabilityTagSet}. * - * @return the ExifInteroperabilityTagSet instance. + * @return the {@code ExifInteroperabilityTagSet} instance. */ public synchronized static ExifInteroperabilityTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifParentTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifParentTIFFTagSet.java index 29647711fc4..108e1a16852 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifParentTIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifParentTIFFTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -80,9 +80,9 @@ public class ExifParentTIFFTagSet extends TIFFTagSet { } /** - * Returns a shared instance of an ExifParentTIFFTagSet. + * Returns a shared instance of an {@code ExifParentTIFFTagSet}. * - * @return an ExifParentTIFFTagSet instance. + * @return an {@code ExifParentTIFFTagSet} instance. */ public synchronized static ExifParentTIFFTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java index 792a78fcb23..c5be97c88c2 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java @@ -33,7 +33,7 @@ import java.util.List; * standard for annotating images used by most digital camera * manufacturers. The Exif specification may be found at * - * http://www.exif.org/Exif2-2.PDF + * {@code http://www.exif.org/Exif2-2.PDF} * . * *

The definitions of the data types referenced by the field @@ -67,7 +67,7 @@ public class ExifTIFFTagSet extends TIFFTagSet { /** * A value to be used with the "ExifVersion" tag to indicate Exif version * 2.1. The value equals the US-ASCII encoding of the byte array - * {'0', '2', '1', '0'}. + * {@code {'0', '2', '1', '0'}}. * * @see #TAG_EXIF_VERSION */ @@ -78,7 +78,7 @@ public class ExifTIFFTagSet extends TIFFTagSet { /** * A value to be used with the "ExifVersion" tag to indicate Exif version * 2.2. The value equals the US-ASCII encoding of the byte array - * {'0', '2', '2', '0'}. + * {@code {'0', '2', '2', '0'}}. * * @see #TAG_EXIF_VERSION */ @@ -94,7 +94,7 @@ public class ExifTIFFTagSet extends TIFFTagSet { /** * A tag indicating the color space information (type SHORT). The - * legal values are given by the COLOR_SPACE_* + * legal values are given by the {@code COLOR_SPACE_*} * constants. * * @see #COLOR_SPACE_SRGB @@ -1992,9 +1992,9 @@ public class ExifTIFFTagSet extends TIFFTagSet { } /** - * Returns a shared instance of an ExifTIFFTagSet. + * Returns a shared instance of an {@code ExifTIFFTagSet}. * - * @return an ExifTIFFTagSet instance. + * @return an {@code ExifTIFFTagSet} instance. */ public synchronized static ExifTIFFTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java index fa9733cd3f0..8a3043da122 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -131,9 +131,9 @@ public class FaxTIFFTagSet extends TIFFTagSet { } /** - * Returns a shared instance of a FaxTIFFTagSet. + * Returns a shared instance of a {@code FaxTIFFTagSet}. * - * @return a FaxTIFFTagSet instance. + * @return a {@code FaxTIFFTagSet} instance. */ public synchronized static FaxTIFFTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java index ec6e5f2a503..28ee56abd3c 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java @@ -32,7 +32,7 @@ import java.util.List; * standard for annotating georeferenced or geocoded raster imagery. * The GeoTIFF specification may be found at - * http://www.remotesensing.org/geotiff/spec/geotiffhome.html + * {@code http://www.remotesensing.org/geotiff/spec/geotiffhome.html} * . This class does not handle the GeoKeys referenced * from a GeoKeyDirectoryTag as those are not TIFF tags per se. * @@ -63,7 +63,7 @@ public class GeoTIFFTagSet extends TIFFTagSet { /** A tag used to store the GeoKey directory. */ public static final int TAG_GEO_KEY_DIRECTORY = 34735; - /** A tag used to store all double-values GeoKeys. */ + /** A tag used to store all {@code double}-values GeoKeys. */ public static final int TAG_GEO_DOUBLE_PARAMS = 34736; /** A tag used to store all ASCII-values GeoKeys. */ @@ -137,9 +137,9 @@ public class GeoTIFFTagSet extends TIFFTagSet { } /** - * Returns a shared instance of a GeoTIFFTagSet. + * Returns a shared instance of a {@code GeoTIFFTagSet}. * - * @return a GeoTIFFTagSet instance. + * @return a {@code GeoTIFFTagSet} instance. */ public synchronized static GeoTIFFTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java index 7f75db646db..f3e5577716a 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java @@ -41,58 +41,58 @@ import com.sun.imageio.plugins.tiff.TIFFImageMetadata; * image metadata. A TIFF image metadata tree represents an Image File * Directory (IFD) from a TIFF 6.0 stream. An IFD consists of a number of * IFD Entries each of which associates an identifying tag number with - * a compatible value. A TIFFDirectory instance corresponds + * a compatible value. A {@code TIFFDirectory} instance corresponds * to an IFD and contains a set of {@link TIFFField}s each of which * corresponds to an IFD Entry in the IFD. * - *

When reading, a TIFFDirectory may be created by passing + *

When reading, a {@code TIFFDirectory} may be created by passing * the value returned by {@link javax.imageio.ImageReader#getImageMetadata * ImageReader.getImageMetadata()} to {@link #createFromMetadata * createFromMetadata()}. The {@link TIFFField}s in the directory may then * be obtained using the accessor methods provided in this class.

* *

When writing, an {@link IIOMetadata} object for use by one of the - * write() methods of {@link javax.imageio.ImageWriter} may be - * created from a TIFFDirectory by {@link #getAsMetadata()}. - * The TIFFDirectory itself may be created by construction or - * from the IIOMetadata object returned by + * {@code write()} methods of {@link javax.imageio.ImageWriter} may be + * created from a {@code TIFFDirectory} by {@link #getAsMetadata()}. + * The {@code TIFFDirectory} itself may be created by construction or + * from the {@code IIOMetadata} object returned by * {@link javax.imageio.ImageWriter#getDefaultImageMetadata - * ImageWriter.getDefaultImageMetadata()}. The TIFFFields in the + * ImageWriter.getDefaultImageMetadata()}. The {@code TIFFField}s in the * directory may be set using the mutator methods provided in this class.

* - *

A TIFFDirectory is aware of the tag numbers in the + *

A {@code TIFFDirectory} is aware of the tag numbers in the * group of {@link TIFFTagSet}s associated with it. When - * a TIFFDirectory is created from a native image metadata + * a {@code TIFFDirectory} is created from a native image metadata * object, these tag sets are derived from the tagSets attribute * of the TIFFIFD node.

* - *

A TIFFDirectory might also have a parent {@link TIFFTag}. + *

A {@code TIFFDirectory} might also have a parent {@link TIFFTag}. * This will occur if the directory represents an IFD other than the root * IFD of the image. The parent tag is the tag of the IFD Entry which is a - * pointer to the IFD represented by this TIFFDirectory. The - * {@link TIFFTag#isIFDPointer} method of this parent TIFFTag - * must return true. When a TIFFDirectory is + * pointer to the IFD represented by this {@code TIFFDirectory}. The + * {@link TIFFTag#isIFDPointer} method of this parent {@code TIFFTag} + * must return {@code true}. When a {@code TIFFDirectory} is * created from a native image metadata object, the parent tag set is set * from the parentTagName attribute of the corresponding - * TIFFIFD node. Note that a TIFFDirectory instance - * which has a non-null parent tag will be contained in the - * data field of a TIFFField instance which has a tag field + * TIFFIFD node. Note that a {@code TIFFDirectory} instance + * which has a non-{@code null} parent tag will be contained in the + * data field of a {@code TIFFField} instance which has a tag field * equal to the contained directory's parent tag.

* - *

As an example consider an Exif image. The TIFFDirectory + *

As an example consider an Exif image. The {@code TIFFDirectory} * instance corresponding to the Exif IFD in the Exif stream would have parent * tag {@link ExifParentTIFFTagSet#TAG_EXIF_IFD_POINTER TAG_EXIF_IFD_POINTER} * and would include {@link ExifTIFFTagSet} in its group of known tag sets. - * The TIFFDirectory corresponding to this Exif IFD will be - * contained in the data field of a TIFFField which will in turn - * be contained in the TIFFDirectory corresponding to the primary - * IFD of the Exif image which will itself have a null-valued + * The {@code TIFFDirectory} corresponding to this Exif IFD will be + * contained in the data field of a {@code TIFFField} which will in turn + * be contained in the {@code TIFFDirectory} corresponding to the primary + * IFD of the Exif image which will itself have a {@code null}-valued * parent tag.

* *

Note that this implementation is not synchronized. If multiple - * threads use a TIFFDirectory instance concurrently, and at + * threads use a {@code TIFFDirectory} instance concurrently, and at * least one of the threads modifies the directory, for example, by adding - * or removing TIFFFields or TIFFTagSets, it + * or removing {@code TIFFField}s or {@code TIFFTagSet}s, it * must be synchronized externally.

* * @since 9 @@ -107,10 +107,10 @@ public class TIFFDirectory implements Cloneable { private static final int MAX_LOW_FIELD_TAG_NUM = BaselineTIFFTagSet.TAG_REFERENCE_BLACK_WHITE; - /** The TIFFTagSets associated with this directory. */ + /** The {@code TIFFTagSets} associated with this directory. */ private List tagSets; - /** The parent TIFFTag of this directory. */ + /** The parent {@code TIFFTag} of this directory. */ private TIFFTag parentTag; /** @@ -123,13 +123,13 @@ public class TIFFDirectory implements Cloneable { private int numLowFields = 0; /** - * A mapping of Integer tag numbers to TIFFFields + * A mapping of {@code Integer} tag numbers to {@code TIFFField}s * for fields which are not low tag numbered. */ private Map highFields = new TreeMap(); /** - * Creates a TIFFDirectory instance from the contents of + * Creates a {@code TIFFDirectory} instance from the contents of * an image metadata object. The supplied object must support an image * metadata format supported by the TIFF {@link javax.imageio.ImageWriter} * plug-in. This will usually be either the TIFF native image metadata @@ -139,12 +139,12 @@ public class TIFFDirectory implements Cloneable { * @param tiffImageMetadata A metadata object which supports a compatible * image metadata format. * - * @return A TIFFDirectory populated from the contents of + * @return A {@code TIFFDirectory} populated from the contents of * the supplied metadata object. * - * @throws NullPointerException if tiffImageMetadata - * is null. - * @throws IllegalArgumentException if tiffImageMetadata + * @throws NullPointerException if {@code tiffImageMetadata} + * is {@code null}. + * @throws IllegalArgumentException if {@code tiffImageMetadata} * does not support a compatible image metadata format. * @throws IIOInvalidTreeException if the supplied metadata object * cannot be parsed. @@ -204,7 +204,7 @@ public class TIFFDirectory implements Cloneable { } /** - * Converts a TIFFDirectory to a TIFFIFD. + * Converts a {@code TIFFDirectory} to a {@code TIFFIFD}. */ private static TIFFIFD getDirectoryAsIFD(TIFFDirectory dir) { if(dir instanceof TIFFIFD) { @@ -242,16 +242,16 @@ public class TIFFDirectory implements Cloneable { } /** - * Constructs a TIFFDirectory which is aware of a given + * Constructs a {@code TIFFDirectory} which is aware of a given * group of {@link TIFFTagSet}s. An optional parent {@link TIFFTag} * may also be specified. * - * @param tagSets The TIFFTagSets associated with this + * @param tagSets The {@code TIFFTagSets} associated with this * directory. - * @param parentTag The parent TIFFTag of this directory; - * may be null. - * @throws NullPointerException if tagSets is - * null. + * @param parentTag The parent {@code TIFFTag} of this directory; + * may be {@code null}. + * @throws NullPointerException if {@code tagSets} is + * {@code null}. */ public TIFFDirectory(TIFFTagSet[] tagSets, TIFFTag parentTag) { if(tagSets == null) { @@ -268,8 +268,8 @@ public class TIFFDirectory implements Cloneable { /** * Returns the {@link TIFFTagSet}s of which this directory is aware. * - * @return The TIFFTagSets associated with this - * TIFFDirectory. + * @return The {@code TIFFTagSet}s associated with this + * {@code TIFFDirectory}. */ public TIFFTagSet[] getTagSets() { return tagSets.toArray(new TIFFTagSet[tagSets.size()]); @@ -279,9 +279,9 @@ public class TIFFDirectory implements Cloneable { * Adds an element to the group of {@link TIFFTagSet}s of which this * directory is aware. * - * @param tagSet The TIFFTagSet to add. - * @throws NullPointerException if tagSet is - * null. + * @param tagSet The {@code TIFFTagSet} to add. + * @throws NullPointerException if {@code tagSet} is + * {@code null}. */ public void addTagSet(TIFFTagSet tagSet) { if(tagSet == null) { @@ -297,9 +297,9 @@ public class TIFFDirectory implements Cloneable { * Removes an element from the group of {@link TIFFTagSet}s of which this * directory is aware. * - * @param tagSet The TIFFTagSet to remove. - * @throws NullPointerException if tagSet is - * null. + * @param tagSet The {@code TIFFTagSet} to remove. + * @throws NullPointerException if {@code tagSet} is + * {@code null}. */ public void removeTagSet(TIFFTagSet tagSet) { if(tagSet == null) { @@ -313,10 +313,10 @@ public class TIFFDirectory implements Cloneable { /** * Returns the parent {@link TIFFTag} of this directory if one - * has been defined or null otherwise. + * has been defined or {@code null} otherwise. * - * @return The parent TIFFTag of this - * TIFFDiectory or null. + * @return The parent {@code TIFFTag} of this + * {@code TIFFDiectory} or {@code null}. */ public TIFFTag getParentTag() { return parentTag; @@ -324,12 +324,12 @@ public class TIFFDirectory implements Cloneable { /** * Returns the {@link TIFFTag} which has tag number equal to - * tagNumber or null if no such tag + * {@code tagNumber} or {@code null} if no such tag * exists in the {@link TIFFTagSet}s associated with this * directory. * * @param tagNumber The tag number of interest. - * @return The corresponding TIFFTag or null. + * @return The corresponding {@code TIFFTag} or {@code null}. */ public TIFFTag getTag(int tagNumber) { return TIFFIFD.getTag(tagNumber, tagSets); @@ -338,8 +338,8 @@ public class TIFFDirectory implements Cloneable { /** * Returns the number of {@link TIFFField}s in this directory. * - * @return The number of TIFFFields in this - * TIFFDirectory. + * @return The number of {@code TIFFField}s in this + * {@code TIFFDirectory}. */ public int getNumTIFFFields() { return numLowFields + highFields.size(); @@ -351,7 +351,7 @@ public class TIFFDirectory implements Cloneable { * * @param tagNumber The tag number. * @return Whether a {@link TIFFTag} with tag number equal to - * tagNumber is present in this TIFFDirectory. + * {@code tagNumber} is present in this {@code TIFFDirectory}. */ public boolean containsTIFFField(int tagNumber) { return (tagNumber >= 0 && tagNumber <= MAX_LOW_FIELD_TAG_NUM && @@ -363,7 +363,7 @@ public class TIFFDirectory implements Cloneable { * Adds a TIFF field to the directory. * * @param f The field to add. - * @throws NullPointerException if f is null. + * @throws NullPointerException if {@code f} is {@code null}. */ public void addTIFFField(TIFFField f) { if(f == null) { @@ -384,8 +384,8 @@ public class TIFFDirectory implements Cloneable { * Retrieves a TIFF field from the directory. * * @param tagNumber The tag number of the tag associated with the field. - * @return A TIFFField with the requested tag number of - * null if no such field is present. + * @return A {@code TIFFField} with the requested tag number of + * {@code null} if no such field is present. */ public TIFFField getTIFFField(int tagNumber) { TIFFField f; @@ -456,7 +456,7 @@ public class TIFFDirectory implements Cloneable { * Converts the directory to a metadata object. * * @return A metadata instance initialized from the contents of this - * TIFFDirectory. + * {@code TIFFDirectory}. */ public IIOMetadata getAsMetadata() { return new TIFFImageMetadata(getDirectoryAsIFD(this)); @@ -465,7 +465,7 @@ public class TIFFDirectory implements Cloneable { /** * Clones the directory and all the fields contained therein. * - * @return A clone of this TIFFDirectory. + * @return A clone of this {@code TIFFDirectory}. * @throws CloneNotSupportedException if the instance cannot be cloned. */ @Override diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java index 010f841315b..336f81550b7 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * *

A field in a TIFF Image File Directory (IFD) is defined as a * tag number accompanied by a sequence of values of identical data type. - * TIFF 6.0 defines 12 data types; a 13th type IFD is + * TIFF 6.0 defines 12 data types; a 13th type {@code IFD} is * defined in TIFF Tech Note 1 of TIFF Specification Supplement 1. These * TIFF data types are referred to by Java constants and mapped internally * onto Java language data types and type names as follows: @@ -68,10 +68,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_BYTE} * * - * byte + * {@code byte} * * - * "Byte" + * {@code "Byte"} * * * @@ -83,10 +83,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_ASCII} * * - * String + * {@code String} * * - * "Ascii" + * {@code "Ascii"} * * * @@ -98,10 +98,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_SHORT} * * - * char + * {@code char} * * - * "Short" + * {@code "Short"} * * * @@ -113,10 +113,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_LONG} * * - * long + * {@code long} * * - * "Long" + * {@code "Long"} * * * @@ -128,10 +128,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_RATIONAL} * * - * long[2] {numerator, denominator} + * {@code long[2]} {numerator, denominator} * * - * "Rational" + * {@code "Rational"} * * * @@ -143,10 +143,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_SBYTE} * * - * byte + * {@code byte} * * - * "SByte" + * {@code "SByte"} * * * @@ -158,10 +158,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_UNDEFINED} * * - * byte + * {@code byte} * * - * "Undefined" + * {@code "Undefined"} * * * @@ -173,10 +173,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_SSHORT} * * - * short + * {@code short} * * - * "SShort" + * {@code "SShort"} * * * @@ -188,10 +188,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_SLONG} * * - * int + * {@code int} * * - * "SLong" + * {@code "SLong"} * * * @@ -203,10 +203,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_SRATIONAL} * * - * int[2] {numerator, denominator} + * {@code int[2]} {numerator, denominator} * * - * "SRational" + * {@code "SRational"} * * * @@ -218,10 +218,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_FLOAT} * * - * float + * {@code float} * * - * "Float" + * {@code "Float"} * * * @@ -233,10 +233,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_DOUBLE} * * - * double + * {@code double} * * - * "Double" + * {@code "Double"} * * * @@ -248,10 +248,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_IFD_POINTER} * * - * long + * {@code long} * * - * "IFDPointer" + * {@code "IFDPointer"} * * * @@ -411,19 +411,19 @@ public class TIFFField implements Cloneable { } /** - * Creates a TIFFField from a TIFF native image + * Creates a {@code TIFFField} from a TIFF native image * metadata node. If the value of the "tagNumber" attribute - * of the node is not found in tagSet then a new - * TIFFTag with name TIFFTag.UNKNOWN_TAG_NAME + * of the node is not found in {@code tagSet} then a new + * {@code TIFFTag} with name {@code TIFFTag.UNKNOWN_TAG_NAME} * will be created and assigned to the field. * - * @param tagSet The TIFFTagSet to which the - * TIFFTag of the field belongs. - * @param node A native TIFF image metadata TIFFField node. - * @throws NullPointerException if node is - * null. + * @param tagSet The {@code TIFFTagSet} to which the + * {@code TIFFTag} of the field belongs. + * @param node A native TIFF image metadata {@code TIFFField} node. + * @throws NullPointerException if {@code node} is + * {@code null}. * @throws IllegalArgumentException if the name of the node is not - * "TIFFField". + * {@code "TIFFField"}. * @return A new {@code TIFFField}. */ public static TIFFField createFromMetadataNode(TIFFTagSet tagSet, @@ -487,14 +487,14 @@ public class TIFFField implements Cloneable { } /** - * Constructs a TIFFField with arbitrary data. The - * type parameter must be a value for which + * Constructs a {@code TIFFField} with arbitrary data. The + * {@code type} parameter must be a value for which * {@link TIFFTag#isDataTypeOK tag.isDataTypeOK()} - * returns true. The data parameter must + * returns {@code true}. The {@code data} parameter must * be an array of a Java type appropriate for the type of the TIFF * field. * - *

Note that the value (data) of the TIFFField + *

Note that the value (data) of the {@code TIFFField} * will always be the actual field value regardless of the number of * bytes required for that value. This is the case despite the fact * that the TIFF IFD Entry corresponding to the field may @@ -503,29 +503,29 @@ public class TIFFField implements Cloneable { * value fits into 4 bytes). In other words, the value of the * field will already have been read from the TIFF stream. (An exception * to this case may occur when the field represents the contents of a - * non-baseline IFD. In that case the data will be a long[] - * containing the offset to the IFD and the TIFFDirectory + * non-baseline IFD. In that case the data will be a {@code long[]} + * containing the offset to the IFD and the {@code TIFFDirectory} * returned by {@link #getDirectory()} will be its contents.) * * @param tag The tag to associated with this field. - * @param type One of the TIFFTag.TIFF_* constants + * @param type One of the {@code TIFFTag.TIFF_*} constants * indicating the data type of the field as written to the TIFF stream. * @param count The number of data values. * @param data The actual data content of the field. * - * @throws NullPointerException if tag == null. - * @throws IllegalArgumentException if type is not - * one of the TIFFTag.TIFF_* data type constants. - * @throws IllegalArgumentException if type is an unacceptable - * data type for the supplied TIFFTag. - * @throws IllegalArgumentException if count < 0. - * @throws IllegalArgumentException if count < 1 - * and type is TIFF_RATIONAL or - * TIFF_SRATIONAL. - * @throws IllegalArgumentException if count ≠ 1 - * and type is TIFF_IFD_POINTER. - * @throws NullPointerException if data == null. - * @throws IllegalArgumentException if data is an instance of + * @throws NullPointerException if {@code tag == null}. + * @throws IllegalArgumentException if {@code type} is not + * one of the {@code TIFFTag.TIFF_*} data type constants. + * @throws IllegalArgumentException if {@code type} is an unacceptable + * data type for the supplied {@code TIFFTag}. + * @throws IllegalArgumentException if {@code count < 0}. + * @throws IllegalArgumentException if {@code count < 1} + * and {@code type} is {@code TIFF_RATIONAL} or + * {@code TIFF_SRATIONAL}. + * @throws IllegalArgumentException if {@code count ≠ 1} + * and {@code type} is {@code TIFF_IFD_POINTER}. + * @throws NullPointerException if {@code data == null}. + * @throws IllegalArgumentException if {@code data} is an instance of * a class incompatible with the specified type. * @throws IllegalArgumentException if the size of the data array is wrong. */ @@ -625,15 +625,15 @@ public class TIFFField implements Cloneable { * parameters and the created array. * * @param tag The tag to associated with this field. - * @param type One of the TIFFTag.TIFF_* constants + * @param type One of the {@code TIFFTag.TIFF_*} constants * indicating the data type of the field as written to the TIFF stream. * @param count The number of data values. - * @throws NullPointerException if tag == null. - * @throws IllegalArgumentException if type is not - * one of the TIFFTag.TIFF_* data type constants. - * @throws IllegalArgumentException if type is an unacceptable - * data type for the supplied TIFFTag. - * @throws IllegalArgumentException if count < 0. + * @throws NullPointerException if {@code tag == null}. + * @throws IllegalArgumentException if {@code type} is not + * one of the {@code TIFFTag.TIFF_*} data type constants. + * @throws IllegalArgumentException if {@code type} is an unacceptable + * data type for the supplied {@code TIFFTag}. + * @throws IllegalArgumentException if {@code count < 0}. * @see #TIFFField(TIFFTag,int,int,Object) */ public TIFFField(TIFFTag tag, int type, int count) { @@ -641,20 +641,20 @@ public class TIFFField implements Cloneable { } /** - * Constructs a TIFFField with a single non-negative integral + * Constructs a {@code TIFFField} with a single non-negative integral * value. * The field will have type * {@link TIFFTag#TIFF_SHORT TIFF_SHORT} if - * val < 65536 and type + * {@code val < 65536} and type * {@link TIFFTag#TIFF_LONG TIFF_LONG} otherwise. The count * of the field will be unity. * * @param tag The tag to associate with this field. * @param value The value to associate with this field. - * @throws NullPointerException if tag == null. + * @throws NullPointerException if {@code tag == null}. * @throws IllegalArgumentException if the derived type is unacceptable - * for the supplied TIFFTag. - * @throws IllegalArgumentException if value < 0. + * for the supplied {@code TIFFTag}. + * @throws IllegalArgumentException if {@code value < 0}. */ public TIFFField(TIFFTag tag, int value) { if(tag == null) { @@ -690,24 +690,24 @@ public class TIFFField implements Cloneable { } /** - * Constructs a TIFFField with an IFD offset and contents. + * Constructs a {@code TIFFField} with an IFD offset and contents. * The offset will be stored as the data of this field as - * long[] {offset}. The directory will not be cloned. The count + * {@code long[] {offset}}. The directory will not be cloned. The count * of the field will be unity. * * @param tag The tag to associated with this field. - * @param type One of the constants TIFFTag.TIFF_LONG or - * TIFFTag.TIFF_IFD_POINTER. + * @param type One of the constants {@code TIFFTag.TIFF_LONG} or + * {@code TIFFTag.TIFF_IFD_POINTER}. * @param offset The IFD offset. * @param dir The directory. * - * @throws NullPointerException if tag == null. - * @throws IllegalArgumentException if type is neither - * TIFFTag.TIFF_LONG nor TIFFTag.TIFF_IFD_POINTER. - * @throws IllegalArgumentException if type is an unacceptable - * data type for the supplied TIFFTag. - * @throws IllegalArgumentException if offset is non-positive. - * @throws NullPointerException if dir == null. + * @throws NullPointerException if {@code tag == null}. + * @throws IllegalArgumentException if {@code type} is neither + * {@code TIFFTag.TIFF_LONG} nor {@code TIFFTag.TIFF_IFD_POINTER}. + * @throws IllegalArgumentException if {@code type} is an unacceptable + * data type for the supplied {@code TIFFTag}. + * @throws IllegalArgumentException if {@code offset} is non-positive. + * @throws NullPointerException if {@code dir == null}. * * @see #TIFFField(TIFFTag,int,int,Object) */ @@ -728,14 +728,14 @@ public class TIFFField implements Cloneable { /** * Retrieves the tag associated with this field. * - * @return The associated TIFFTag. + * @return The associated {@code TIFFTag}. */ public TIFFTag getTag() { return tag; } /** - * Retrieves the tag number in the range [0, 65535]. + * Retrieves the tag number in the range {@code [0, 65535]}. * * @return The tag number. */ @@ -745,7 +745,7 @@ public class TIFFField implements Cloneable { /** * Returns the type of the data stored in the field. For a TIFF 6.0 - * stream, the value will equal one of the TIFFTag.TIFF_* + * stream, the value will equal one of the {@code TIFFTag.TIFF_*} * constants. For future revisions of TIFF, higher values are possible. * * @return The data type of the field value. @@ -757,11 +757,11 @@ public class TIFFField implements Cloneable { /** * Returns the name of the supplied data type constant. * - * @param dataType One of the TIFFTag.TIFF_* constants + * @param dataType One of the {@code TIFFTag.TIFF_*} constants * indicating the data type of the field as written to the TIFF stream. * @return The type name corresponding to the supplied type constant. - * @throws IllegalArgumentException if dataType is not - * one of the TIFFTag.TIFF_* data type constants. + * @throws IllegalArgumentException if {@code dataType} is not + * one of the {@code TIFFTag.TIFF_*} data type constants. */ public static String getTypeName(int dataType) { if (dataType < TIFFTag.MIN_DATATYPE || @@ -774,11 +774,11 @@ public class TIFFField implements Cloneable { /** * Returns the data type constant corresponding to the supplied data - * type name. If the name is unknown -1 will be returned. + * type name. If the name is unknown {@code -1} will be returned. * * @param typeName The type name. - * @return One of the TIFFTag.TIFF_* constants or - * -1 if the name is not recognized. + * @return One of the {@code TIFFTag.TIFF_*} constants or + * {@code -1} if the name is not recognized. */ public static int getTypeByName(String typeName) { for (int i = TIFFTag.MIN_DATATYPE; i <= TIFFTag.MAX_DATATYPE; i++) { @@ -793,14 +793,14 @@ public class TIFFField implements Cloneable { /** * Creates an array appropriate for the indicated data type. * - * @param dataType One of the TIFFTag.TIFF_* data type + * @param dataType One of the {@code TIFFTag.TIFF_*} data type * constants. * @param count The number of values in the array. * @return An array appropriate for the specified data type. * - * @throws IllegalArgumentException if dataType is not - * one of the TIFFTag.TIFF_* data type constants. - * @throws IllegalArgumentException if count < 0. + * @throws IllegalArgumentException if {@code dataType} is not + * one of the {@code TIFFTag.TIFF_*} data type constants. + * @throws IllegalArgumentException if {@code count < 0}. */ public static Object createArrayForType(int dataType, int count) { if(count < 0) { @@ -836,15 +836,15 @@ public class TIFFField implements Cloneable { } /** - * Returns the TIFFField as a node named either + * Returns the {@code TIFFField} as a node named either * "TIFFField" or "TIFFIFD" as described in the * TIFF native image metadata specification. The node will be named * "TIFFIFD" if and only if the field's data object is an * instance of {@link TIFFDirectory} or equivalently * {@link TIFFTag#isIFDPointer getTag.isIFDPointer()} returns - * true. + * {@code true}. * - * @return a Node named "TIFFField" or + * @return a {@code Node} named "TIFFField" or * "TIFFIFD". */ public Node getAsNativeNode() { @@ -863,8 +863,8 @@ public class TIFFField implements Cloneable { /** * Returns the number of data items present in the field. For - * TIFFTag.TIFF_ASCII fields, the value returned is the - * number of Strings, not the total length of the + * {@code TIFFTag.TIFF_ASCII} fields, the value returned is the + * number of {@code String}s, not the total length of the * data as in the file representation. * * @return The number of data items present in the field. @@ -884,17 +884,17 @@ public class TIFFField implements Cloneable { /** * Returns the data as an uninterpreted array of - * bytes. The type of the field must be one of - * TIFFTag.TIFF_BYTE, TIFF_SBYTE, or - * TIFF_UNDEFINED. + * {@code byte}s. The type of the field must be one of + * {@code TIFFTag.TIFF_BYTE}, {@code TIFF_SBYTE}, or + * {@code TIFF_UNDEFINED}. * - *

For data in TIFFTag.TIFF_BYTE format, the application + *

For data in {@code TIFFTag.TIFF_BYTE} format, the application * must take care when promoting the data to longer integral types * to avoid sign extension. * * @throws ClassCastException if the field is not of type - * TIFF_BYTE, TIFF_SBYTE, or - * TIFF_UNDEFINED. + * {@code TIFF_BYTE}, {@code TIFF_SBYTE}, or + * {@code TIFF_UNDEFINED}. * @return The data as an uninterpreted array of bytes. */ public byte[] getAsBytes() { @@ -902,11 +902,11 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_SHORT data as an array of - * chars (unsigned 16-bit integers). + * Returns {@code TIFFTag.TIFF_SHORT} data as an array of + * {@code char}s (unsigned 16-bit integers). * * @throws ClassCastException if the field is not of type - * TIFF_SHORT. + * {@code TIFF_SHORT}. * @return The data as an array of {@code char}s. */ public char[] getAsChars() { @@ -914,11 +914,11 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_SSHORT data as an array of - * shorts (signed 16-bit integers). + * Returns {@code TIFFTag.TIFF_SSHORT} data as an array of + * {@code short}s (signed 16-bit integers). * * @throws ClassCastException if the field is not of type - * TIFF_SSHORT. + * {@code TIFF_SSHORT}. * @return The data as an array of {@code short}s. */ public short[] getAsShorts() { @@ -926,12 +926,12 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_SLONG data as an array of - * ints (signed 32-bit integers). + * Returns {@code TIFFTag.TIFF_SLONG} data as an array of + * {@code int}s (signed 32-bit integers). * * @throws ClassCastException if the field is not of type - * TIFF_SHORT, TIFF_SSHORT, or - * TIFF_SLONG. + * {@code TIFF_SHORT}, {@code TIFF_SSHORT}, or + * {@code TIFF_SLONG}. * @return The data as an array of {@code int}s. */ public int[] getAsInts() { @@ -957,12 +957,12 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_LONG or - * TIFF_IFD_POINTER data as an array of - * longs (signed 64-bit integers). + * Returns {@code TIFFTag.TIFF_LONG} or + * {@code TIFF_IFD_POINTER} data as an array of + * {@code long}s (signed 64-bit integers). * * @throws ClassCastException if the field is not of type - * TIFF_LONG or TIFF_IFD_POINTER. + * {@code TIFF_LONG} or {@code TIFF_IFD_POINTER}. * @return The data as an array of {@code long}s. */ public long[] getAsLongs() { @@ -970,11 +970,11 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_FLOAT data as an array of - * floats (32-bit floating-point values). + * Returns {@code TIFFTag.TIFF_FLOAT} data as an array of + * {@code float}s (32-bit floating-point values). * * @throws ClassCastException if the field is not of type - * TIFF_FLOAT. + * {@code TIFF_FLOAT}. * @return The data as an array of {@code float}s. */ public float[] getAsFloats() { @@ -982,11 +982,11 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_DOUBLE data as an array of - * doubles (64-bit floating-point values). + * Returns {@code TIFFTag.TIFF_DOUBLE} data as an array of + * {@code double}s (64-bit floating-point values). * * @throws ClassCastException if the field is not of type - * TIFF_DOUBLE. + * {@code TIFF_DOUBLE}. * @return The data as an array of {@code double}s. */ public double[] getAsDoubles() { @@ -994,11 +994,11 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_SRATIONAL data as an array of - * 2-element arrays of ints. + * Returns {@code TIFFTag.TIFF_SRATIONAL} data as an array of + * 2-element arrays of {@code int}s. * * @throws ClassCastException if the field is not of type - * TIFF_SRATIONAL. + * {@code TIFF_SRATIONAL}. * @return The data as an array of signed rationals. */ public int[][] getAsSRationals() { @@ -1006,11 +1006,11 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_RATIONAL data as an array of - * 2-element arrays of longs. + * Returns {@code TIFFTag.TIFF_RATIONAL} data as an array of + * 2-element arrays of {@code long}s. * * @throws ClassCastException if the field is not of type - * TIFF_RATIONAL. + * {@code TIFF_RATIONAL}. * @return The data as an array of unsigned rationals. */ public long[][] getAsRationals() { @@ -1018,30 +1018,30 @@ public class TIFFField implements Cloneable { } /** - * Returns data in any format as an int. + * Returns data in any format as an {@code int}. * - *

TIFFTag.TIFF_BYTE values are treated as unsigned; that + *

{@code TIFFTag.TIFF_BYTE} values are treated as unsigned; that * is, no sign extension will take place and the returned value - * will be in the range [0, 255]. TIFF_SBYTE data + * will be in the range [0, 255]. {@code TIFF_SBYTE} data * will be returned in the range [-128, 127]. * - *

A TIFF_UNDEFINED value is treated as though - * it were a TIFF_BYTE. + *

A {@code TIFF_UNDEFINED} value is treated as though + * it were a {@code TIFF_BYTE}. * - *

Data in TIFF_SLONG, TIFF_LONG, - * TIFF_FLOAT, TIFF_DOUBLE or - * TIFF_IFD_POINTER format are simply cast to - * int and may suffer from truncation. + *

Data in {@code TIFF_SLONG}, {@code TIFF_LONG}, + * {@code TIFF_FLOAT}, {@code TIFF_DOUBLE} or + * {@code TIFF_IFD_POINTER} format are simply cast to + * {@code int} and may suffer from truncation. * - *

Data in TIFF_SRATIONAL or - * TIFF_RATIONAL format are evaluated by dividing the + *

Data in {@code TIFF_SRATIONAL} or + * {@code TIFF_RATIONAL} format are evaluated by dividing the * numerator into the denominator using double-precision - * arithmetic and then casting to int. Loss of + * arithmetic and then casting to {@code int}. Loss of * precision and truncation may occur. * - *

Data in TIFF_ASCII format will be parsed as by - * the Double.parseDouble method, with the result - * case to int. + *

Data in {@code TIFF_ASCII} format will be parsed as by + * the {@code Double.parseDouble} method, with the result + * case to {@code int}. * * @param index The index of the data. * @return The data at the given index as an {@code int}. @@ -1081,17 +1081,17 @@ public class TIFFField implements Cloneable { } /** - * Returns data in any format as a long. + * Returns data in any format as a {@code long}. * - *

TIFFTag.TIFF_BYTE and TIFF_UNDEFINED data + *

{@code TIFFTag.TIFF_BYTE} and {@code TIFF_UNDEFINED} data * are treated as unsigned; that is, no sign extension will take * place and the returned value will be in the range [0, 255]. - * TIFF_SBYTE data will be returned in the range + * {@code TIFF_SBYTE} data will be returned in the range * [-128, 127]. * - *

Data in TIFF_ASCII format will be parsed as by - * the Double.parseDouble method, with the result - * cast to long. + *

Data in {@code TIFF_ASCII} format will be parsed as by + * the {@code Double.parseDouble} method, with the result + * cast to {@code long}. * * @param index The index of the data. * @return The data at the given index as a {@code long}. @@ -1127,27 +1127,27 @@ public class TIFFField implements Cloneable { } /** - * Returns data in any format as a float. + * Returns data in any format as a {@code float}. * - *

TIFFTag.TIFF_BYTE and TIFF_UNDEFINED data + *

{@code TIFFTag.TIFF_BYTE} and {@code TIFF_UNDEFINED} data * are treated as unsigned; that is, no sign extension will take * place and the returned value will be in the range [0, 255]. - * TIFF_SBYTE data will be returned in the range + * {@code TIFF_SBYTE} data will be returned in the range * [-128, 127]. * - *

Data in TIFF_SLONG, TIFF_LONG, - * TIFF_DOUBLE, or TIFF_IFD_POINTER format are - * simply cast to float and may suffer from + *

Data in {@code TIFF_SLONG}, {@code TIFF_LONG}, + * {@code TIFF_DOUBLE}, or {@code TIFF_IFD_POINTER} format are + * simply cast to {@code float} and may suffer from * truncation. * - *

Data in TIFF_SRATIONAL or - * TIFF_RATIONAL format are evaluated by dividing the + *

Data in {@code TIFF_SRATIONAL} or + * {@code TIFF_RATIONAL} format are evaluated by dividing the * numerator into the denominator using double-precision - * arithmetic and then casting to float. + * arithmetic and then casting to {@code float}. * - *

Data in TIFF_ASCII format will be parsed as by - * the Double.parseDouble method, with the result - * cast to float. + *

Data in {@code TIFF_ASCII} format will be parsed as by + * the {@code Double.parseDouble} method, with the result + * cast to {@code float}. * * @param index The index of the data. * @return The data at the given index as a {@code float}. @@ -1187,21 +1187,21 @@ public class TIFFField implements Cloneable { } /** - * Returns data in any format as a double. + * Returns data in any format as a {@code double}. * - *

TIFFTag.TIFF_BYTE and TIFF_UNDEFINED data + *

{@code TIFFTag.TIFF_BYTE} and {@code TIFF_UNDEFINED} data * are treated as unsigned; that is, no sign extension will take * place and the returned value will be in the range [0, 255]. - * TIFF_SBYTE data will be returned in the range + * {@code TIFF_SBYTE} data will be returned in the range * [-128, 127]. * - *

Data in TIFF_SRATIONAL or - * TIFF_RATIONAL format are evaluated by dividing the + *

Data in {@code TIFF_SRATIONAL} or + * {@code TIFF_RATIONAL} format are evaluated by dividing the * numerator into the denominator using double-precision * arithmetic. * - *

Data in TIFF_ASCII format will be parsed as by - * the Double.parseDouble method. + *

Data in {@code TIFF_ASCII} format will be parsed as by + * the {@code Double.parseDouble} method. * * @param index The index of the data. * @return The data at the given index as a {@code double}. @@ -1241,11 +1241,11 @@ public class TIFFField implements Cloneable { } /** - * Returns a TIFFTag.TIFF_ASCII value as a - * String. + * Returns a {@code TIFFTag.TIFF_ASCII} value as a + * {@code String}. * * @throws ClassCastException if the field is not of type - * TIFF_ASCII. + * {@code TIFF_ASCII}. * * @param index The index of the data. * @return The data at the given index as a {@code String}. @@ -1255,13 +1255,13 @@ public class TIFFField implements Cloneable { } /** - * Returns a TIFFTag.TIFF_SRATIONAL data item as a - * two-element array of ints. + * Returns a {@code TIFFTag.TIFF_SRATIONAL} data item as a + * two-element array of {@code int}s. * * @param index The index of the data. * @return The data at the given index as a signed rational. * @throws ClassCastException if the field is not of type - * TIFF_SRATIONAL. + * {@code TIFF_SRATIONAL}. */ public int[] getAsSRational(int index) { return ((int[][])data)[index]; @@ -1274,7 +1274,7 @@ public class TIFFField implements Cloneable { * @param index The index of the data. * @return The data at the given index as an unsigned rational. * @throws ClassCastException if the field is not of type - * TIFF_RATIONAL. + * {@code TIFF_RATIONAL}. */ public long[] getAsRational(int index) { return ((long[][])data)[index]; @@ -1282,11 +1282,11 @@ public class TIFFField implements Cloneable { /** - * Returns a String containing a human-readable + * Returns a {@code String} containing a human-readable * version of the data item. Data of type - * TIFFTag.TIFF_RATIONAL or TIFF_SRATIONAL are + * {@code TIFFTag.TIFF_RATIONAL} or {@code TIFF_SRATIONAL} are * represented as a pair of integers separated by a - * '/' character. + * {@code '/'} character. * * @param index The index of the data. * @return The data at the given index as a {@code String}. @@ -1355,7 +1355,7 @@ public class TIFFField implements Cloneable { } /** - * Returns whether the field has a TIFFDirectory. + * Returns whether the field has a {@code TIFFDirectory}. * * @return true if and only if getDirectory() returns non-null. */ @@ -1364,8 +1364,8 @@ public class TIFFField implements Cloneable { } /** - * Returns the associated TIFFDirectory, if available. If no - * directory is set, then null will be returned. + * Returns the associated {@code TIFFDirectory}, if available. If no + * directory is set, then {@code null} will be returned. * * @return the TIFFDirectory instance or null. */ @@ -1376,7 +1376,7 @@ public class TIFFField implements Cloneable { /** * Clones the field and all the information contained therein. * - * @return A clone of this TIFFField. + * @return A clone of this {@code TIFFField}. * @throws CloneNotSupportedException if the instance cannot be cloned. */ @Override diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java index 27f633c7cfd..9c120d094ef 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -39,11 +39,11 @@ import javax.imageio.ImageReadParam; * be provided by this interface. * *

Additional TIFF tags must be organized into - * TIFFTagSets. A TIFFTagSet may be + * {@code TIFFTagSet}s. A {@code TIFFTagSet} may be * provided to the reader by means of the - * addAllowedTagSet method. By default, the tag sets - * BaselineTIFFTagSet, FaxTIFFTagSet, - * ExifParentTIFFTagSet, and GeoTIFFTagSet + * {@code addAllowedTagSet} method. By default, the tag sets + * {@code BaselineTIFFTagSet}, {@code FaxTIFFTagSet}, + * {@code ExifParentTIFFTagSet}, and {@code GeoTIFFTagSet} * are included. * * @since 9 @@ -53,10 +53,10 @@ public class TIFFImageReadParam extends ImageReadParam { private List allowedTagSets = new ArrayList(4); /** - * Constructs a TIFFImageReadParam. Tags defined by - * the TIFFTagSets BaselineTIFFTagSet, - * FaxTIFFTagSet, ExifParentTIFFTagSet, and - * GeoTIFFTagSet will be supported. + * Constructs a {@code TIFFImageReadParam}. Tags defined by + * the {@code TIFFTagSet}s {@code BaselineTIFFTagSet}, + * {@code FaxTIFFTagSet}, {@code ExifParentTIFFTagSet}, and + * {@code GeoTIFFTagSet} will be supported. * * @see BaselineTIFFTagSet * @see FaxTIFFTagSet @@ -71,13 +71,13 @@ public class TIFFImageReadParam extends ImageReadParam { } /** - * Adds a TIFFTagSet object to the list of allowed + * Adds a {@code TIFFTagSet} object to the list of allowed * tag sets. * - * @param tagSet a TIFFTagSet. + * @param tagSet a {@code TIFFTagSet}. * - * @throws IllegalArgumentException if tagSet is - * null. + * @throws IllegalArgumentException if {@code tagSet} is + * {@code null}. */ public void addAllowedTagSet(TIFFTagSet tagSet) { if (tagSet == null) { @@ -87,15 +87,15 @@ public class TIFFImageReadParam extends ImageReadParam { } /** - * Removes a TIFFTagSet object from the list of - * allowed tag sets. Removal is based on the equals - * method of the TIFFTagSet, which is normally + * Removes a {@code TIFFTagSet} object from the list of + * allowed tag sets. Removal is based on the {@code equals} + * method of the {@code TIFFTagSet}, which is normally * defined as reference equality. * - * @param tagSet a TIFFTagSet. + * @param tagSet a {@code TIFFTagSet}. * - * @throws IllegalArgumentException if tagSet is - * null. + * @throws IllegalArgumentException if {@code tagSet} is + * {@code null}. */ public void removeAllowedTagSet(TIFFTagSet tagSet) { if (tagSet == null) { @@ -105,10 +105,10 @@ public class TIFFImageReadParam extends ImageReadParam { } /** - * Returns a List containing the allowed - * TIFFTagSet objects. + * Returns a {@code List} containing the allowed + * {@code TIFFTagSet} objects. * - * @return a List of TIFFTagSets. + * @return a {@code List} of {@code TIFFTagSet}s. */ public List getAllowedTagSets() { return allowedTagSets; diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTag.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTag.java index 68542c4078d..c312bd55419 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTag.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -105,7 +105,7 @@ public class TIFFTag { * The name assigned to a tag with an unknown tag number. Such * a tag may be created for example when reading an IFD and a * tag number is encountered which is not in any of the - * TIFFTagSets known to the reader. + * {@code TIFFTagSet}s known to the reader. */ public static final String UNKNOWN_TAG_NAME = "UnknownTag"; @@ -141,12 +141,12 @@ public class TIFFTag { private SortedMap valueNames = null; /** - * Constructs a TIFFTag with a given name, tag number, set + * Constructs a {@code TIFFTag} with a given name, tag number, set * of legal data types, and value count. A negative value count signifies * that either an arbitrary number of values is legal or the required count * is determined by the values of other fields in the IFD. A non-negative * count specifies the number of values which an associated field must - * contain. The tag will have no associated TIFFTagSet. + * contain. The tag will have no associated {@code TIFFTagSet}. * *

If there are mnemonic names to be associated with the legal * data values for the tag, {@link #addValueName(int, String) @@ -183,18 +183,18 @@ public class TIFFTag { } /** - * Constructs a TIFFTag with a given name, tag number and - * TIFFTagSet to which it refers. The legal data types are + * Constructs a {@code TIFFTag} with a given name, tag number and + * {@code TIFFTagSet} to which it refers. The legal data types are * set to include {@link #TIFF_LONG} and {@link #TIFF_IFD_POINTER} and the - * value count is unity. The TIFFTagSet will - * represent the set of TIFFTags which appear in the IFD - * pointed to. A TIFFTag represents an IFD pointer if and - * only if tagSet is non-null or the data - * type TIFF_IFD_POINTER is legal. + * value count is unity. The {@code TIFFTagSet} will + * represent the set of {@code TIFFTag}s which appear in the IFD + * pointed to. A {@code TIFFTag} represents an IFD pointer if and + * only if {@code tagSet} is non-{@code null} or the data + * type {@code TIFF_IFD_POINTER} is legal. * * @param name the name of the tag. * @param number the number used to represent the tag. - * @param tagSet the TIFFTagSet to which this tag belongs. + * @param tagSet the {@code TIFFTagSet} to which this tag belongs. * @throws NullPointerException if name or tagSet is null. * @throws IllegalArgumentException if number is negative. * @@ -210,9 +210,9 @@ public class TIFFTag { } /** - * Constructs a TIFFTag with a given name, tag number, + * Constructs a {@code TIFFTag} with a given name, tag number, * and set of legal data types. The value count of the tag will be - * undefined and it will have no associated TIFFTagSet. + * undefined and it will have no associated {@code TIFFTagSet}. * * @param name the name of the tag. * @param number the number used to represent the tag. @@ -236,9 +236,9 @@ public class TIFFTag { * * @return the number of bytes used to store the given data type. * - * @throws IllegalArgumentException if datatype is - * less than MIN_DATATYPE or greater than - * MAX_DATATYPE. + * @throws IllegalArgumentException if {@code datatype} is + * less than {@code MIN_DATATYPE} or greater than + * {@code MAX_DATATYPE}. */ public static int getSizeOfType(int dataType) { if (dataType < MIN_DATATYPE ||dataType > MAX_DATATYPE) { @@ -251,7 +251,7 @@ public class TIFFTag { /** * Returns the name of the tag, as it will appear in image metadata. * - * @return the tag name, as a String. + * @return the tag name, as a {@code String}. */ public String getName() { return name; @@ -260,7 +260,7 @@ public class TIFFTag { /** * Returns the integer used to represent the tag. * - * @return the tag number, as an int. + * @return the tag number, as an {@code int}. */ public int getNumber() { return number; @@ -276,7 +276,7 @@ public class TIFFTag { * (1 << TIFFTag.TIFF_SHORT) | (1 << TIFFTag.TIFF_LONG) * * - * @return an int containing a bitmask encoding the + * @return an {@code int} containing a bitmask encoding the * set of valid data types. */ public int getDataTypes() { @@ -285,11 +285,11 @@ public class TIFFTag { /** * Returns the value count of this tag. If this value is positive, it - * represents the required number of values for a TIFFField + * represents the required number of values for a {@code TIFFField} * which has this tag. If the value is negative, the count is undefined. * In the latter case the count may be derived, e.g., the number of values - * of the BitsPerSample field is SamplesPerPixel, - * or it may be variable as in the case of most US-ASCII + * of the {@code BitsPerSample} field is {@code SamplesPerPixel}, + * or it may be variable as in the case of most {@code US-ASCII} * fields. * * @return the value count of this tag. @@ -299,18 +299,18 @@ public class TIFFTag { } /** - * Returns true if the given data type + * Returns {@code true} if the given data type * may be used for the data associated with this tag. * * @param dataType the data type to be queried, one of - * TIFF_BYTE, TIFF_SHORT, etc. + * {@code TIFF_BYTE}, {@code TIFF_SHORT}, etc. * - * @return a boolean indicating whether the given + * @return a {@code boolean} indicating whether the given * data type may be used with this tag. * - * @throws IllegalArgumentException if datatype is - * less than MIN_DATATYPE or greater than - * MAX_DATATYPE. + * @throws IllegalArgumentException if {@code datatype} is + * less than {@code MIN_DATATYPE} or greater than + * {@code MAX_DATATYPE}. */ public boolean isDataTypeOK(int dataType) { if (dataType < MIN_DATATYPE || dataType > MAX_DATATYPE) { @@ -320,38 +320,38 @@ public class TIFFTag { } /** - * Returns the TIFFTagSet of which this tag is a part. + * Returns the {@code TIFFTagSet} of which this tag is a part. * - * @return the containing TIFFTagSet. + * @return the containing {@code TIFFTagSet}. */ public TIFFTagSet getTagSet() { return tagSet; } /** - * Returns true if this tag is used to point to an IFD - * structure containing additional tags. A TIFFTag represents - * an IFD pointer if and only if its TIFFTagSet is - * non-null or the data type TIFF_IFD_POINTER is + * Returns {@code true} if this tag is used to point to an IFD + * structure containing additional tags. A {@code TIFFTag} represents + * an IFD pointer if and only if its {@code TIFFTagSet} is + * non-{@code null} or the data type {@code TIFF_IFD_POINTER} is * legal. This condition will be satisfied if and only if either - * getTagSet() != null or - * isDataTypeOK(TIFF_IFD_POINTER) == true. + * {@code getTagSet() != null} or + * {@code isDataTypeOK(TIFF_IFD_POINTER) == true}. * *

Many TIFF extensions use the IFD mechanism in order to limit the * number of new tags that may appear in the root IFD.

* - * @return true if this tag points to an IFD. + * @return {@code true} if this tag points to an IFD. */ public boolean isIFDPointer() { return tagSet != null || isDataTypeOK(TIFF_IFD_POINTER); } /** - * Returns true if there are mnemonic names associated with + * Returns {@code true} if there are mnemonic names associated with * the set of legal values for the data associated with this tag. Mnemonic * names apply only to tags which have integral data type. * - * @return true if mnemonic value names are available. + * @return {@code true} if mnemonic value names are available. */ public boolean hasValueNames() { return valueNames != null; @@ -373,14 +373,14 @@ public class TIFFTag { /** * Returns the mnemonic name associated with a particular value - * that this tag's data may take on, or null if + * that this tag's data may take on, or {@code null} if * no name is present. Mnemonic names apply only to tags which have * integral data type. * * @param value the data value. * * @return the mnemonic name associated with the value, as a - * String. + * {@code String}. */ public String getValueName(int value) { if (valueNames == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTagSet.java index 8082fba86b8..793bafce1b7 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -39,7 +39,7 @@ import java.util.TreeSet; * specification itself). * *

This class and its subclasses are responsible for mapping - * between raw tag numbers and TIFFTag objects, which + * between raw tag numbers and {@code TIFFTag} objects, which * contain additional information about each tag, such as the tag's * name, legal data types, and mnemonic names for some or all of ts * data values. @@ -59,15 +59,15 @@ public class TIFFTagSet { private TIFFTagSet() {} /** - * Constructs a TIFFTagSet, given a List - * of TIFFTag objects. + * Constructs a {@code TIFFTagSet}, given a {@code List} + * of {@code TIFFTag} objects. * - * @param tags a List object containing - * TIFFTag objects to be added to this tag set. + * @param tags a {@code List} object containing + * {@code TIFFTag} objects to be added to this tag set. * - * @throws IllegalArgumentException if tags is - * null, or contains objects that are not instances - * of the TIFFTag class. + * @throws IllegalArgumentException if {@code tags} is + * {@code null}, or contains objects that are not instances + * of the {@code TIFFTag} class. */ public TIFFTagSet(List tags) { if (tags == null) { @@ -88,29 +88,29 @@ public class TIFFTagSet { } /** - * Returns the TIFFTag from this set that is - * associated with the given tag number, or null if + * Returns the {@code TIFFTag} from this set that is + * associated with the given tag number, or {@code null} if * no tag exists for that number. * * @param tagNumber the number of the tag to be retrieved. * - * @return the numbered TIFFTag, or null. + * @return the numbered {@code TIFFTag}, or {@code null}. */ public TIFFTag getTag(int tagNumber) { return allowedTagsByNumber.get(Integer.valueOf(tagNumber)); } /** - * Returns the TIFFTag having the given tag name, or - * null if the named tag does not belong to this tag set. + * Returns the {@code TIFFTag} having the given tag name, or + * {@code null} if the named tag does not belong to this tag set. * * @param tagName the name of the tag to be retrieved, as a - * String. + * {@code String}. * - * @return the named TIFFTag, or null. + * @return the named {@code TIFFTag}, or {@code null}. * - * @throws IllegalArgumentException if tagName is - * null. + * @throws IllegalArgumentException if {@code tagName} is + * {@code null}. */ public TIFFTag getTag(String tagName) { if (tagName == null) { @@ -123,7 +123,7 @@ public class TIFFTagSet { * Retrieves an unmodifiable numerically increasing set of tag numbers. * *

The returned object is unmodifiable and contains the tag - * numbers of all TIFFTags in this TIFFTagSet + * numbers of all {@code TIFFTag}s in this {@code TIFFTagSet} * sorted into ascending order according to * {@link Integer#compareTo(Object)}.

* @@ -145,7 +145,7 @@ public class TIFFTagSet { * Retrieves an unmodifiable lexicographically increasing set of tag names. * *

The returned object is unmodifiable and contains the tag - * names of all TIFFTags in this TIFFTagSet + * names of all {@code TIFFTag}s in this {@code TIFFTagSet} * sorted into ascending order according to * {@link String#compareTo(Object)}.

* From 4e4a6d18abe0f4633947128e16c29987ce34dd99 Mon Sep 17 00:00:00 2001 From: Ambarish Rapte Date: Mon, 15 Feb 2016 14:36:54 +0530 Subject: [PATCH 007/183] 8025001: setFocusTraversalPolicy() to ContainerOrderFocusTraversalPolicy results in an infinite loop Reviewed-by: ssadetsky, psadhukhan --- .../ContainerOrderFocusTraversalPolicy.java | 4 +- .../ContainerOrderFTPTest.java | 90 +++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/awt/Focus/FocusTraversalPolicy/ContainerOrderFTPTest.java diff --git a/jdk/src/java.desktop/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java b/jdk/src/java.desktop/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java index d23e672779c..9b04496f65b 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java +++ b/jdk/src/java.desktop/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java @@ -231,7 +231,9 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy // Before all the checks below we first see if it's an FTP provider or a focus cycle root. // If it's the case just go down cycle (if it's set to "implicit"). Component comp = getComponentDownCycle(aComponent, FORWARD_TRAVERSAL); - if (comp != null) { + // Check if aComponent is focus-cycle-root's default Component, i.e. + // focus cycle root & focus-cycle-root's default Component is same. + if (comp != null && comp != aComponent) { return comp; } diff --git a/jdk/test/java/awt/Focus/FocusTraversalPolicy/ContainerOrderFTPTest.java b/jdk/test/java/awt/Focus/FocusTraversalPolicy/ContainerOrderFTPTest.java new file mode 100644 index 00000000000..5957204ee79 --- /dev/null +++ b/jdk/test/java/awt/Focus/FocusTraversalPolicy/ContainerOrderFTPTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 8025001 + @summary Tests java.awt.ContainerOrderFocusTraversalPolicy functionality. + @run main ContainerOrderFTPTest +*/ + +import java.awt.Frame; +import java.awt.Button; +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.ContainerOrderFocusTraversalPolicy; + +public class ContainerOrderFTPTest { + + private final ContainerOrderFocusTraversalPolicy coftp; + private final Frame frame; + private final Button b1; + private final Button b2; + private final String expectedTraversal; + + public ContainerOrderFTPTest() { + expectedTraversal = "B1B2F1"; + b1 = new Button("B1"); + b2 = new Button("B2"); + frame = new Frame("F1"); + + frame.setLayout(new FlowLayout()); + frame.setSize(200, 200); + coftp = new ContainerOrderFocusTraversalPolicy(); + frame.setFocusTraversalPolicy(coftp); + frame.add(b1); + frame.add(b2); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + ContainerOrderFTPTest test = new ContainerOrderFTPTest(); + test.performTest(); + test.dispose(); + } + + public void performTest() { + int count = 0; + Component comp = coftp.getFirstComponent(frame); + String traversal = ""; + do { + comp = coftp.getComponentAfter(frame, comp); + if (comp instanceof Button) { + traversal += ((Button)comp).getLabel(); + } else if (comp instanceof Frame) { + traversal += ((Frame)comp).getTitle(); + } + count++; + } while(count < 3); + + if (!expectedTraversal.equals(traversal)) { + dispose(); + throw new RuntimeException("Incorrect Traversal. Expected : " + + expectedTraversal + "Actual : " + traversal); + } + } + + public void dispose() { + frame.dispose(); + } +} From 0b936de72ace703e09d5f2100b8197a89d52123a Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 12 Feb 2016 16:08:39 +0300 Subject: [PATCH 008/183] 8130061: java.beans.EventHandler.create does not specify how it fails when an EventHandler cannot be created Reviewed-by: alanb --- .../share/classes/java/beans/EventHandler.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/java/beans/EventHandler.java b/jdk/src/java.desktop/share/classes/java/beans/EventHandler.java index 6f1427fe54a..1ab720f7555 100644 --- a/jdk/src/java.desktop/share/classes/java/beans/EventHandler.java +++ b/jdk/src/java.desktop/share/classes/java/beans/EventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, 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 @@ -526,8 +526,11 @@ public class EventHandler implements InvocationHandler { * @throws NullPointerException if {@code listenerInterface} is null * @throws NullPointerException if {@code target} is null * @throws NullPointerException if {@code action} is null - * + * @throws IllegalArgumentException if creating a Proxy for + * {@code listenerInterface} fails for any of the restrictions + * specified by {@link Proxy#newProxyInstance} * @see #create(Class, Object, String, String) + * @see Proxy#newProxyInstance */ public static T create(Class listenerInterface, Object target, String action) @@ -584,8 +587,11 @@ public class EventHandler implements InvocationHandler { * @throws NullPointerException if {@code listenerInterface} is null * @throws NullPointerException if {@code target} is null * @throws NullPointerException if {@code action} is null - * + * @throws IllegalArgumentException if creating a Proxy for + * {@code listenerInterface} fails for any of the restrictions + * specified by {@link Proxy#newProxyInstance} * @see #create(Class, Object, String, String, String) + * @see Proxy#newProxyInstance */ public static T create(Class listenerInterface, Object target, String action, @@ -675,8 +681,11 @@ public class EventHandler implements InvocationHandler { * @throws NullPointerException if {@code listenerInterface} is null * @throws NullPointerException if {@code target} is null * @throws NullPointerException if {@code action} is null - * + * @throws IllegalArgumentException if creating a Proxy for + * {@code listenerInterface} fails for any of the restrictions + * specified by {@link Proxy#newProxyInstance} * @see EventHandler + * @see Proxy#newProxyInstance */ public static T create(Class listenerInterface, Object target, String action, From 8eb27fd4d39087b3f12cf7156ceedc9d6fd88cb7 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 12 Feb 2016 16:09:39 +0300 Subject: [PATCH 009/183] 8136382: SimpleBeanInfo.loadImage succeeds when running with a security manager Reviewed-by: alanb --- .../classes/java/beans/SimpleBeanInfo.java | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/java/beans/SimpleBeanInfo.java b/jdk/src/java.desktop/share/classes/java/beans/SimpleBeanInfo.java index ddef0cffad5..ba2cbcd2dc9 100644 --- a/jdk/src/java.desktop/share/classes/java/beans/SimpleBeanInfo.java +++ b/jdk/src/java.desktop/share/classes/java/beans/SimpleBeanInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, 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 @@ -27,7 +27,8 @@ package java.beans; import java.awt.Image; import java.awt.Toolkit; -import java.io.InputStream; +import java.awt.image.ImageProducer; +import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; @@ -171,19 +172,24 @@ public class SimpleBeanInfo implements BeanInfo { } /** - * This is a utility method to help in loading icon images. - * It takes the name of a resource file associated with the - * current object's class file and loads an image object - * from that file. Typically images will be GIFs. + * This is a utility method to help in loading icon images. It takes the + * name of a resource file associated with the current object's class file + * and loads an image object from that file. Typically images will be GIFs. * - * @param resourceName A pathname relative to the directory - * holding the class file of the current class. For example, - * "wombat.gif". - * @return an image object. May be null if the load failed. + * @param resourceName A pathname relative to the directory holding the + * class file of the current class. For example, "wombat.gif". + * @return an image object or null if the resource is not found or the + * resource could not be loaded as an Image */ public Image loadImage(final String resourceName) { - try (InputStream in = getClass().getResourceAsStream(resourceName)) { - return Toolkit.getDefaultToolkit().createImage(in.readAllBytes()); + try { + final URL url = getClass().getResource(resourceName); + if (url != null) { + final ImageProducer ip = (ImageProducer) url.getContent(); + if (ip != null) { + return Toolkit.getDefaultToolkit().createImage(ip); + } + } } catch (final Exception ignored) { } return null; From 0e441f9177eb9852be6a47f8e7b0afcf39d89342 Mon Sep 17 00:00:00 2001 From: Pavel Punegov Date: Wed, 17 Feb 2016 17:48:56 +0300 Subject: [PATCH 010/183] 8144621: CompilerControl: inline tests timeout with Xcomp Restrict patterns that lead to timeout Reviewed-by: kvn, neliasso --- .../compiler/compilercontrol/share/AbstractTestBase.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java b/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java index 2e1c2013b43..04d8ada9319 100644 --- a/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java +++ b/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java @@ -51,8 +51,9 @@ public abstract class AbstractTestBase { for (int i = 0; !md.isValid() && i < ATTEMPTS; i++) { md = METHOD_GEN.generateRandomDescriptor(exec); } - if (!md.isValid()) { - System.out.println("WARN: Using predefined pattern"); + if (!md.isValid() || "any.method()".matches(md.getRegexp())) { + /* if we haven't got a valid pattern or it matches any method + leading to timeouts, then use plain standard descriptor */ md = MethodGenerator.commandDescriptor(exec); } return md; From b239e217b925411aa043d2022dad19a97fb892e7 Mon Sep 17 00:00:00 2001 From: Rahul Raghavan Date: Fri, 19 Feb 2016 10:06:19 +0100 Subject: [PATCH 011/183] 8145707: 4 Null pointer dereference defect groups in compileBroker.cpp Added explicit null checks to fix possible null pointer dereference errors for internal tests. Reviewed-by: kvn --- .../src/share/vm/compiler/compileBroker.cpp | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 117e7d130ba..44903801d83 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -2152,18 +2152,33 @@ void CompileBroker::collect_statistics(CompilerThread* thread, elapsedTimer time if (CITime) { int bytes_compiled = method->code_size() + task->num_inlined_bytecodes(); - JVMCI_ONLY(CompilerStatistics* stats = compiler(task->comp_level())->stats();) if (is_osr) { _t_osr_compilation.add(time); _sum_osr_bytes_compiled += bytes_compiled; - JVMCI_ONLY(stats->_osr.update(time, bytes_compiled);) } else { _t_standard_compilation.add(time); _sum_standard_bytes_compiled += method->code_size() + task->num_inlined_bytecodes(); - JVMCI_ONLY(stats->_standard.update(time, bytes_compiled);) } - JVMCI_ONLY(stats->_nmethods_size += code->total_size();) - JVMCI_ONLY(stats->_nmethods_code_size += code->insts_size();) + +#if INCLUDE_JVMCI + AbstractCompiler* comp = compiler(task->comp_level()); + if (comp) { + CompilerStatistics* stats = comp->stats(); + if (stats) { + if (is_osr) { + stats->_osr.update(time, bytes_compiled); + } else { + stats->_standard.update(time, bytes_compiled); + } + stats->_nmethods_size += code->total_size(); + stats->_nmethods_code_size += code->insts_size(); + } else { // if (!stats) + assert(false, "Compiler statistics object must exist"); + } + } else { // if (!comp) + assert(false, "Compiler object must exist"); + } +#endif // INCLUDE_JVMCI } if (UsePerfData) { @@ -2222,11 +2237,15 @@ const char* CompileBroker::compiler_name(int comp_level) { #if INCLUDE_JVMCI void CompileBroker::print_times(AbstractCompiler* comp) { CompilerStatistics* stats = comp->stats(); - tty->print_cr(" %s {speed: %d bytes/s; standard: %6.3f s, %d bytes, %d methods; osr: %6.3f s, %d bytes, %d methods; nmethods_size: %d bytes; nmethods_code_size: %d bytes}", + if (stats) { + tty->print_cr(" %s {speed: %d bytes/s; standard: %6.3f s, %d bytes, %d methods; osr: %6.3f s, %d bytes, %d methods; nmethods_size: %d bytes; nmethods_code_size: %d bytes}", comp->name(), stats->bytes_per_second(), stats->_standard._time.seconds(), stats->_standard._bytes, stats->_standard._count, stats->_osr._time.seconds(), stats->_osr._bytes, stats->_osr._count, stats->_nmethods_size, stats->_nmethods_code_size); + } else { // if (!stats) + assert(false, "Compiler statistics object must exist"); + } comp->print_timers(); } #endif // INCLUDE_JVMCI @@ -2260,17 +2279,21 @@ void CompileBroker::print_times(bool per_compiler, bool aggregate) { } CompilerStatistics* stats = comp->stats(); - standard_compilation.add(stats->_standard._time); - osr_compilation.add(stats->_osr._time); + if (stats) { + standard_compilation.add(stats->_standard._time); + osr_compilation.add(stats->_osr._time); - standard_bytes_compiled += stats->_standard._bytes; - osr_bytes_compiled += stats->_osr._bytes; + standard_bytes_compiled += stats->_standard._bytes; + osr_bytes_compiled += stats->_osr._bytes; - standard_compile_count += stats->_standard._count; - osr_compile_count += stats->_osr._count; + standard_compile_count += stats->_standard._count; + osr_compile_count += stats->_osr._count; - nmethods_size += stats->_nmethods_size; - nmethods_code_size += stats->_nmethods_code_size; + nmethods_size += stats->_nmethods_size; + nmethods_code_size += stats->_nmethods_code_size; + } else { // if (!stats) + assert(false, "Compiler statistics object must exist"); + } if (per_compiler) { print_times(comp); From 4532f543002d8093241791877e20333235790e4f Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 19 Feb 2016 20:40:20 +0300 Subject: [PATCH 012/183] 7177745: JSR292: Many Callsite relinkages cause target method to always run in interpreter mode Reviewed-by: jrose, kvn --- hotspot/src/share/vm/code/codeCache.cpp | 2 +- hotspot/src/share/vm/code/codeCache.hpp | 4 +- hotspot/src/share/vm/code/dependencies.hpp | 10 ++ .../src/share/vm/code/dependencyContext.cpp | 2 +- hotspot/src/share/vm/code/nmethod.cpp | 4 +- hotspot/src/share/vm/code/nmethod.hpp | 21 +++- hotspot/src/share/vm/oops/instanceKlass.cpp | 2 +- hotspot/src/share/vm/oops/instanceKlass.hpp | 4 +- hotspot/src/share/vm/runtime/vmStructs.cpp | 1 - .../ContinuousCallSiteTargetChange.java | 103 ++++++++++++++++++ 10 files changed, 140 insertions(+), 13 deletions(-) create mode 100644 hotspot/test/compiler/jsr292/ContinuousCallSiteTargetChange.java diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index c7c31c30d3b..0882ee82739 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -1023,7 +1023,7 @@ void CodeCache::clear_inline_caches() { // Keeps track of time spent for checking dependencies NOT_PRODUCT(static elapsedTimer dependentCheckTime;) -int CodeCache::mark_for_deoptimization(DepChange& changes) { +int CodeCache::mark_for_deoptimization(KlassDepChange& changes) { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); int number_of_marked_CodeBlobs = 0; diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp index a3da713c9e5..f07b4c940db 100644 --- a/hotspot/src/share/vm/code/codeCache.hpp +++ b/hotspot/src/share/vm/code/codeCache.hpp @@ -72,7 +72,7 @@ // Solaris and BSD. class OopClosure; -class DepChange; +class KlassDepChange; class CodeCache : AllStatic { friend class VMStructs; @@ -223,7 +223,7 @@ class CodeCache : AllStatic { // Deoptimization private: - static int mark_for_deoptimization(DepChange& changes); + static int mark_for_deoptimization(KlassDepChange& changes); #ifdef HOTSWAP static int mark_for_evol_deoptimization(instanceKlassHandle dependee); #endif // HOTSWAP diff --git a/hotspot/src/share/vm/code/dependencies.hpp b/hotspot/src/share/vm/code/dependencies.hpp index b62c6bf12ed..22a2fd2ce53 100644 --- a/hotspot/src/share/vm/code/dependencies.hpp +++ b/hotspot/src/share/vm/code/dependencies.hpp @@ -664,6 +664,8 @@ class DepChange : public StackObj { virtual bool is_klass_change() const { return false; } virtual bool is_call_site_change() const { return false; } + virtual void mark_for_deoptimization(nmethod* nm) = 0; + // Subclass casting with assertions. KlassDepChange* as_klass_change() { assert(is_klass_change(), "bad cast"); @@ -753,6 +755,10 @@ class KlassDepChange : public DepChange { // What kind of DepChange is this? virtual bool is_klass_change() const { return true; } + virtual void mark_for_deoptimization(nmethod* nm) { + nm->mark_for_deoptimization(/*inc_recompile_counts=*/true); + } + Klass* new_type() { return _new_type(); } // involves_context(k) is true if k is new_type or any of the super types @@ -772,6 +778,10 @@ class CallSiteDepChange : public DepChange { // What kind of DepChange is this? virtual bool is_call_site_change() const { return true; } + virtual void mark_for_deoptimization(nmethod* nm) { + nm->mark_for_deoptimization(/*inc_recompile_counts=*/false); + } + oop call_site() const { return _call_site(); } oop method_handle() const { return _method_handle(); } }; diff --git a/hotspot/src/share/vm/code/dependencyContext.cpp b/hotspot/src/share/vm/code/dependencyContext.cpp index dc19c4a0886..435fb0cdfb2 100644 --- a/hotspot/src/share/vm/code/dependencyContext.cpp +++ b/hotspot/src/share/vm/code/dependencyContext.cpp @@ -73,7 +73,7 @@ int DependencyContext::mark_dependent_nmethods(DepChange& changes) { nm->print(); nm->print_dependencies(); } - nm->mark_for_deoptimization(); + changes.mark_for_deoptimization(nm); found++; } } diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 63acd8f424d..46fe64850e4 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -536,7 +536,7 @@ void nmethod::init_defaults() { _has_method_handle_invokes = 0; _lazy_critical_native = 0; _has_wide_vectors = 0; - _marked_for_deoptimization = 0; + _mark_for_deoptimization_status = not_marked; _lock_count = 0; _stack_traversal_mark = 0; _unload_reported = false; // jvmti state @@ -1459,7 +1459,7 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { SharedRuntime::get_handle_wrong_method_stub()); } - if (is_in_use()) { + if (is_in_use() && update_recompile_counts()) { // It's a true state change, so mark the method as decompiled. // Do it only for transition from alive. inc_decompile_count(); diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 537a68ce566..6c0d9f839ac 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -107,6 +107,7 @@ class PcDescCache VALUE_OBJ_CLASS_SPEC { // [Implicit Null Pointer exception table] // - implicit null table array +class DepChange; class Dependencies; class ExceptionHandlerTable; class ImplicitExceptionTable; @@ -188,7 +189,13 @@ class nmethod : public CodeBlob { bool _has_flushed_dependencies; // Used for maintenance of dependencies (CodeCache_lock) bool _marked_for_reclamation; // Used by NMethodSweeper (set only by sweeper) - bool _marked_for_deoptimization; // Used for stack deoptimization + + enum MarkForDeoptimizationStatus { + not_marked, + deoptimize, + deoptimize_noupdate }; + + MarkForDeoptimizationStatus _mark_for_deoptimization_status; // Used for stack deoptimization // used by jvmti to track if an unload event has been posted for this nmethod. bool _unload_reported; @@ -462,8 +469,16 @@ class nmethod : public CodeBlob { void set_unloading_clock(unsigned char unloading_clock); unsigned char unloading_clock(); - bool is_marked_for_deoptimization() const { return _marked_for_deoptimization; } - void mark_for_deoptimization() { _marked_for_deoptimization = true; } + bool is_marked_for_deoptimization() const { return _mark_for_deoptimization_status != not_marked; } + void mark_for_deoptimization(bool inc_recompile_counts = true) { + _mark_for_deoptimization_status = (inc_recompile_counts ? deoptimize : deoptimize_noupdate); + } + bool update_recompile_counts() const { + // Update recompile counts when either the update is explicitly requested (deoptimize) + // or the nmethod is not marked for deoptimization at all (not_marked). + // The latter happens during uncommon traps when deoptimized nmethod is made not entrant. + return _mark_for_deoptimization_status != deoptimize_noupdate; + } void make_unloaded(BoolObjectClosure* is_alive, oop cause); diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 0ae310bdaf6..d1297af03df 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -1879,7 +1879,7 @@ inline DependencyContext InstanceKlass::dependencies() { return dep_context; } -int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { +int InstanceKlass::mark_dependent_nmethods(KlassDepChange& changes) { return dependencies().mark_dependent_nmethods(changes); } diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index f7a3a24800f..aa3604f8997 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -56,7 +56,7 @@ // forward declaration for class -- see below for definition class BreakpointInfo; class ClassFileParser; -class DepChange; +class KlassDepChange; class DependencyContext; class fieldDescriptor; class jniIdMapBase; @@ -821,7 +821,7 @@ public: // maintenance of deoptimization dependencies inline DependencyContext dependencies(); - int mark_dependent_nmethods(DepChange& changes); + int mark_dependent_nmethods(KlassDepChange& changes); void add_dependent_nmethod(nmethod* nm); void remove_dependent_nmethod(nmethod* nm, bool delete_immediately); diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index c6519c03600..0778abc2f7a 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -960,7 +960,6 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(nmethod, _compile_id, int) \ nonstatic_field(nmethod, _comp_level, int) \ nonstatic_field(nmethod, _exception_cache, ExceptionCache*) \ - nonstatic_field(nmethod, _marked_for_deoptimization, bool) \ \ unchecked_c2_static_field(Deoptimization, _trap_reason_name, void*) \ \ diff --git a/hotspot/test/compiler/jsr292/ContinuousCallSiteTargetChange.java b/hotspot/test/compiler/jsr292/ContinuousCallSiteTargetChange.java new file mode 100644 index 00000000000..a59f962fd22 --- /dev/null +++ b/hotspot/test/compiler/jsr292/ContinuousCallSiteTargetChange.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /testlibrary + * @run main ContinuousCallSiteTargetChange + */ +import java.lang.invoke.*; +import jdk.test.lib.*; + +public class ContinuousCallSiteTargetChange { + static void testServer() throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", + "-server", "-XX:-TieredCompilation", "-Xbatch", + "-XX:PerBytecodeRecompilationCutoff=10", "-XX:PerMethodRecompilationCutoff=10", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "ContinuousCallSiteTargetChange$Test", "100"); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldNotContain("made not compilable"); + analyzer.shouldNotContain("decompile_count > PerMethodRecompilationCutoff"); + } + + static void testClient() throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", + "-client", "-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1", "-Xbatch", + "-XX:PerBytecodeRecompilationCutoff=10", "-XX:PerMethodRecompilationCutoff=10", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "ContinuousCallSiteTargetChange$Test", "100"); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldNotContain("made not compilable"); + analyzer.shouldNotContain("decompile_count > PerMethodRecompilationCutoff"); + } + + public static void main(String[] args) throws Exception { + testServer(); + testClient(); + } + + static class Test { + static final MethodType mt = MethodType.methodType(void.class); + static final CallSite cs = new MutableCallSite(mt); + + static final MethodHandle mh = cs.dynamicInvoker(); + + static void f() { + } + + static void test1() throws Throwable { + mh.invokeExact(); + } + + static void test2() throws Throwable { + cs.getTarget().invokeExact(); + } + + static void iteration() throws Throwable { + MethodHandle mh1 = MethodHandles.lookup().findStatic(ContinuousCallSiteTargetChange.Test.class, "f", mt); + cs.setTarget(mh1); + for (int i = 0; i < 20_000; i++) { + test1(); + test2(); + } + } + + public static void main(String[] args) throws Throwable { + int iterations = Integer.parseInt(args[0]); + for (int i = 0; i < iterations; i++) { + iteration(); + } + } + } +} From 78fbdd19fa16e09b06d694b77a3ea86e941e30a8 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 19 Feb 2016 20:41:36 +0300 Subject: [PATCH 013/183] 8149741: Don't refer to stub entry points by index in external_word relocations Reviewed-by: kvn --- .../vm/templateInterpreterGenerator_x86.cpp | 8 +-- .../windows_x86/vm/assembler_windows_x86.cpp | 5 +- hotspot/src/share/vm/code/relocInfo.cpp | 68 ++----------------- hotspot/src/share/vm/code/relocInfo.hpp | 11 +-- .../share/vm/prims/jvmtiCodeBlobEvents.cpp | 4 +- .../share/vm/runtime/stubCodeGenerator.cpp | 53 ++++----------- .../share/vm/runtime/stubCodeGenerator.hpp | 15 ++-- 7 files changed, 30 insertions(+), 134 deletions(-) diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp index eb155c20be9..fc69cb45e5b 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp @@ -161,13 +161,7 @@ address TemplateInterpreterGenerator::generate_exception_handler_common( create_klass_exception), rarg, rarg2); } else { - // kind of lame ExternalAddress can't take NULL because - // external_word_Relocation will assert. - if (message != NULL) { - __ lea(rarg2, ExternalAddress((address)message)); - } else { - __ movptr(rarg2, NULL_WORD); - } + __ lea(rarg2, ExternalAddress((address)message)); __ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), rarg, rarg2); diff --git a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp index 71e1e8b6aad..8045f792b76 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp +++ b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp @@ -51,11 +51,8 @@ void MacroAssembler::int3() { // movl reg, [reg + thread_ptr_offset] Load thread // void MacroAssembler::get_thread(Register thread) { - // can't use ExternalAddress because it can't take NULL - AddressLiteral null(0, relocInfo::none); - prefix(FS_segment); - movptr(thread, null); + movptr(thread, ExternalAddress(NULL)); assert(os::win32::get_thread_ptr_offset() != 0, "Thread Pointer Offset has not been initialized"); movl(thread, Address(thread, os::win32::get_thread_ptr_offset())); diff --git a/hotspot/src/share/vm/code/relocInfo.cpp b/hotspot/src/share/vm/code/relocInfo.cpp index ec83dad64a8..444c91c46be 100644 --- a/hotspot/src/share/vm/code/relocInfo.cpp +++ b/hotspot/src/share/vm/code/relocInfo.cpp @@ -457,49 +457,6 @@ RelocationHolder Relocation::spec_simple(relocInfo::relocType rtype) { return itr._rh; } -int32_t Relocation::runtime_address_to_index(address runtime_address) { - assert(!is_reloc_index((intptr_t)runtime_address), "must not look like an index"); - - if (runtime_address == NULL) return 0; - - StubCodeDesc* p = StubCodeDesc::desc_for(runtime_address); - if (p != NULL && p->begin() == runtime_address) { - assert(is_reloc_index(p->index()), "there must not be too many stubs"); - return (int32_t)p->index(); - } else { - // Known "miscellaneous" non-stub pointers: - // os::get_polling_page(), SafepointSynchronize::address_of_state() - if (PrintRelocations) { - tty->print_cr("random unregistered address in relocInfo: " INTPTR_FORMAT, p2i(runtime_address)); - } -#ifndef _LP64 - return (int32_t) (intptr_t)runtime_address; -#else - // didn't fit return non-index - return -1; -#endif /* _LP64 */ - } -} - - -address Relocation::index_to_runtime_address(int32_t index) { - if (index == 0) return NULL; - - if (is_reloc_index(index)) { - StubCodeDesc* p = StubCodeDesc::desc_for_index(index); - assert(p != NULL, "there must be a stub for this index"); - return p->begin(); - } else { -#ifndef _LP64 - // this only works on 32bit machines - return (address) ((intptr_t) index); -#else - fatal("Relocation::index_to_runtime_address, int32_t not pointer sized"); - return NULL; -#endif /* _LP64 */ - } -} - address Relocation::old_addr_for(address newa, const CodeBuffer* src, CodeBuffer* dest) { int sect = dest->section_index_of(newa); @@ -623,20 +580,13 @@ void trampoline_stub_Relocation::unpack_data() { void external_word_Relocation::pack_data_to(CodeSection* dest) { short* p = (short*) dest->locs_end(); - int32_t index = runtime_address_to_index(_target); #ifndef _LP64 - p = pack_1_int_to(p, index); + p = pack_1_int_to(p, (int32_t) (intptr_t)_target); #else - if (is_reloc_index(index)) { - p = pack_2_ints_to(p, index, 0); - } else { - jlong t = (jlong) _target; - int32_t lo = low(t); - int32_t hi = high(t); - p = pack_2_ints_to(p, lo, hi); - DEBUG_ONLY(jlong t1 = jlong_from(hi, lo)); - assert(!is_reloc_index(t1) && (address) t1 == _target, "not symmetric"); - } + jlong t = (jlong) _target; + int32_t lo = low(t); + int32_t hi = high(t); + p = pack_2_ints_to(p, lo, hi); #endif /* _LP64 */ dest->set_locs_end((relocInfo*) p); } @@ -644,16 +594,12 @@ void external_word_Relocation::pack_data_to(CodeSection* dest) { void external_word_Relocation::unpack_data() { #ifndef _LP64 - _target = index_to_runtime_address(unpack_1_int()); + _target = (address) (intptr_t)unpack_1_int(); #else int32_t lo, hi; unpack_2_ints(lo, hi); jlong t = jlong_from(hi, lo);; - if (is_reloc_index(t)) { - _target = index_to_runtime_address(t); - } else { - _target = (address) t; - } + _target = (address) t; #endif /* _LP64 */ } diff --git a/hotspot/src/share/vm/code/relocInfo.hpp b/hotspot/src/share/vm/code/relocInfo.hpp index a243bfdbee7..b399c093759 100644 --- a/hotspot/src/share/vm/code/relocInfo.hpp +++ b/hotspot/src/share/vm/code/relocInfo.hpp @@ -707,10 +707,6 @@ class Relocation VALUE_OBJ_CLASS_SPEC { assert(datalen()==0 || type()==relocInfo::none, "no data here"); } - static bool is_reloc_index(intptr_t index) { - return 0 < index && index < os::vm_page_size(); - } - protected: // Helper functions for pack_data_to() and unpack_data(). @@ -806,10 +802,6 @@ class Relocation VALUE_OBJ_CLASS_SPEC { return base + byte_offset; } - // these convert between indexes and addresses in the runtime system - static int32_t runtime_address_to_index(address runtime_address); - static address index_to_runtime_address(int32_t index); - // helpers for mapping between old and new addresses after a move or resize address old_addr_for(address newa, const CodeBuffer* src, CodeBuffer* dest); address new_addr_for(address olda, const CodeBuffer* src, CodeBuffer* dest); @@ -1253,7 +1245,8 @@ class external_word_Relocation : public DataRelocation { // Some address looking values aren't safe to treat as relocations // and should just be treated as constants. static bool can_be_relocated(address target) { - return target != NULL && !is_reloc_index((intptr_t)target); + assert(target == NULL || (uintptr_t)target >= (uintptr_t)os::vm_page_size(), INTPTR_FORMAT, (intptr_t)target); + return target != NULL; } private: diff --git a/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp b/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp index 3031f1c4e5b..975836cd32a 100644 --- a/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp +++ b/hotspot/src/share/vm/prims/jvmtiCodeBlobEvents.cpp @@ -173,9 +173,7 @@ void CodeBlobCollector::collect() { _global_code_blobs = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(50,true); // iterate over the stub code descriptors and put them in the list first. - int index = 0; - StubCodeDesc* desc; - while ((desc = StubCodeDesc::desc_for_index(++index)) != NULL) { + for (StubCodeDesc* desc = StubCodeDesc::first(); desc != NULL; desc = StubCodeDesc::next(desc)) { _global_code_blobs->append(new JvmtiCodeBlobDesc(desc->name(), desc->begin(), desc->end())); } diff --git a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp index 5b9adc09776..db440291575 100644 --- a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp +++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp @@ -36,19 +36,13 @@ // Implementation of StubCodeDesc StubCodeDesc* StubCodeDesc::_list = NULL; -int StubCodeDesc::_count = 0; bool StubCodeDesc::_frozen = false; StubCodeDesc* StubCodeDesc::desc_for(address pc) { StubCodeDesc* p = _list; - while (p != NULL && !p->contains(pc)) p = p->_next; - // p == NULL || p->contains(pc) - return p; -} - -StubCodeDesc* StubCodeDesc::desc_for_index(int index) { - StubCodeDesc* p = _list; - while (p != NULL && p->index() != index) p = p->_next; + while (p != NULL && !p->contains(pc)) { + p = p->_next; + } return p; } @@ -73,43 +67,17 @@ void StubCodeDesc::print_on(outputStream* st) const { // Implementation of StubCodeGenerator StubCodeGenerator::StubCodeGenerator(CodeBuffer* code, bool print_code) { - _masm = new MacroAssembler(code); - _first_stub = _last_stub = NULL; - _print_code = print_code; -} - -extern "C" { - static int compare_cdesc(const void* void_a, const void* void_b) { - int ai = (*((StubCodeDesc**) void_a))->index(); - int bi = (*((StubCodeDesc**) void_b))->index(); - return ai - bi; - } + _masm = new MacroAssembler(code ); + _print_code = PrintStubCode || print_code; } StubCodeGenerator::~StubCodeGenerator() { - if (PrintStubCode || _print_code) { + if (_print_code) { CodeBuffer* cbuf = _masm->code(); CodeBlob* blob = CodeCache::find_blob_unsafe(cbuf->insts()->start()); if (blob != NULL) { blob->set_strings(cbuf->strings()); } - bool saw_first = false; - StubCodeDesc* toprint[1000]; - int toprint_len = 0; - for (StubCodeDesc* cdesc = _last_stub; cdesc != NULL; cdesc = cdesc->_next) { - toprint[toprint_len++] = cdesc; - if (cdesc == _first_stub) { saw_first = true; break; } - } - assert(toprint_len == 0 || saw_first, "must get both first & last"); - // Print in reverse order: - qsort(toprint, toprint_len, sizeof(toprint[0]), compare_cdesc); - for (int i = 0; i < toprint_len; i++) { - StubCodeDesc* cdesc = toprint[i]; - cdesc->print(); - tty->cr(); - Disassembler::decode(cdesc->begin(), cdesc->end()); - tty->cr(); - } } } @@ -118,9 +86,12 @@ void StubCodeGenerator::stub_prolog(StubCodeDesc* cdesc) { } void StubCodeGenerator::stub_epilog(StubCodeDesc* cdesc) { - // default implementation - record the cdesc - if (_first_stub == NULL) _first_stub = cdesc; - _last_stub = cdesc; + if (_print_code) { + cdesc->print(); + tty->cr(); + Disassembler::decode(cdesc->begin(), cdesc->end()); + tty->cr(); + } } diff --git a/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp b/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp index 13bb86e6396..4571e3ae667 100644 --- a/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp +++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp @@ -39,13 +39,11 @@ class StubCodeDesc: public CHeapObj { private: static StubCodeDesc* _list; // the list of all descriptors - static int _count; // length of list static bool _frozen; // determines whether _list modifications are allowed StubCodeDesc* _next; // the next element in the linked list const char* _group; // the group to which the stub code belongs const char* _name; // the name assigned to the stub code - int _index; // serial number assigned to the stub address _begin; // points to the first byte of the stub code (included) address _end; // points to the first byte after the stub code (excluded) @@ -64,8 +62,10 @@ class StubCodeDesc: public CHeapObj { friend class StubCodeGenerator; public: + static StubCodeDesc* first() { return _list; } + static StubCodeDesc* next(StubCodeDesc* desc) { return desc->_next; } + static StubCodeDesc* desc_for(address pc); // returns the code descriptor for the code containing pc or NULL - static StubCodeDesc* desc_for_index(int); // returns the code descriptor for the index or NULL static const char* name_for(address pc); // returns the name of the code containing pc or NULL StubCodeDesc(const char* group, const char* name, address begin, address end = NULL) { @@ -74,7 +74,6 @@ class StubCodeDesc: public CHeapObj { _next = _list; _group = group; _name = name; - _index = ++_count; // (never zero) _begin = begin; _end = end; _list = this; @@ -84,7 +83,6 @@ class StubCodeDesc: public CHeapObj { const char* group() const { return _group; } const char* name() const { return _name; } - int index() const { return _index; } address begin() const { return _begin; } address end() const { return _end; } int size_in_bytes() const { return _end - _begin; } @@ -97,13 +95,12 @@ class StubCodeDesc: public CHeapObj { // Provides utility functions. class StubCodeGenerator: public StackObj { + private: + bool _print_code; + protected: MacroAssembler* _masm; - StubCodeDesc* _first_stub; - StubCodeDesc* _last_stub; - bool _print_code; - public: StubCodeGenerator(CodeBuffer* code, bool print_code = false); ~StubCodeGenerator(); From a026f88a38d044a21f224897a21b3095e7d2f898 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 19 Feb 2016 20:45:26 +0300 Subject: [PATCH 014/183] 8067014: LinearScan::is_sorted significantly slows down fastdebug builds' performance Reviewed-by: vlivanov, shade --- hotspot/src/share/vm/c1/c1_CFGPrinter.hpp | 6 +- hotspot/src/share/vm/c1/c1_LinearScan.cpp | 119 ++++++++++++++-------- hotspot/src/share/vm/c1/c1_LinearScan.hpp | 6 +- 3 files changed, 83 insertions(+), 48 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_CFGPrinter.hpp b/hotspot/src/share/vm/c1/c1_CFGPrinter.hpp index 1cdde1186b2..00790396214 100644 --- a/hotspot/src/share/vm/c1/c1_CFGPrinter.hpp +++ b/hotspot/src/share/vm/c1/c1_CFGPrinter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -34,7 +34,9 @@ // compilation for later analysis. class CFGPrinterOutput; -class IntervalList; +class Interval; + +typedef GrowableArray IntervalList; class CFGPrinter : public AllStatic { private: diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.cpp b/hotspot/src/share/vm/c1/c1_LinearScan.cpp index cda969cb4b8..eb49e97d896 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -1434,42 +1434,74 @@ int LinearScan::interval_cmp(Interval** a, Interval** b) { } #ifndef PRODUCT -bool LinearScan::is_sorted(IntervalArray* intervals) { - int from = -1; - int i, j; - for (i = 0; i < intervals->length(); i ++) { - Interval* it = intervals->at(i); - if (it != NULL) { - if (from > it->from()) { - assert(false, ""); - return false; - } - from = it->from(); +int interval_cmp(Interval* const& l, Interval* const& r) { + return l->from() - r->from(); +} + +bool find_interval(Interval* interval, IntervalArray* intervals) { + bool found; + int idx = intervals->find_sorted(interval, found); + + if (!found) { + return false; + } + + int from = interval->from(); + + // The index we've found using binary search is pointing to an interval + // that is defined in the same place as the interval we were looking for. + // So now we have to look around that index and find exact interval. + for (int i = idx; i >= 0; i--) { + if (intervals->at(i) == interval) { + return true; + } + if (intervals->at(i)->from() != from) { + break; } } - // check in both directions if sorted list and unsorted list contain same intervals - for (i = 0; i < interval_count(); i++) { - if (interval_at(i) != NULL) { - int num_found = 0; - for (j = 0; j < intervals->length(); j++) { - if (interval_at(i) == intervals->at(j)) { - num_found++; - } - } - assert(num_found == 1, "lists do not contain same intervals"); + for (int i = idx + 1; i < intervals->length(); i++) { + if (intervals->at(i) == interval) { + return true; + } + if (intervals->at(i)->from() != from) { + break; } } - for (j = 0; j < intervals->length(); j++) { - int num_found = 0; - for (i = 0; i < interval_count(); i++) { - if (interval_at(i) == intervals->at(j)) { - num_found++; - } + + return false; +} + +bool LinearScan::is_sorted(IntervalArray* intervals) { + int from = -1; + int null_count = 0; + + for (int i = 0; i < intervals->length(); i++) { + Interval* it = intervals->at(i); + if (it != NULL) { + assert(from <= it->from(), "Intervals are unordered"); + from = it->from(); + } else { + null_count++; } - assert(num_found == 1, "lists do not contain same intervals"); } + assert(null_count == 0, "Sorted intervals should not contain nulls"); + + null_count = 0; + + for (int i = 0; i < interval_count(); i++) { + Interval* interval = interval_at(i); + if (interval != NULL) { + assert(find_interval(interval, intervals), "Lists do not contain same intervals"); + } else { + null_count++; + } + } + + assert(interval_count() - null_count == intervals->length(), + "Sorted list should contain the same amount of non-NULL intervals as unsorted list"); + return true; } #endif @@ -1536,7 +1568,7 @@ void LinearScan::sort_intervals_before_allocation() { sorted_len++; } } - IntervalArray* sorted_list = new IntervalArray(sorted_len); + IntervalArray* sorted_list = new IntervalArray(sorted_len, sorted_len, NULL); // special sorting algorithm: the original interval-list is almost sorted, // only some intervals are swapped. So this is much faster than a complete QuickSort @@ -1574,8 +1606,8 @@ void LinearScan::sort_intervals_after_allocation() { _needs_full_resort = false; } - IntervalArray* old_list = _sorted_intervals; - IntervalList* new_list = _new_intervals_from_allocation; + IntervalArray* old_list = _sorted_intervals; + IntervalList* new_list = _new_intervals_from_allocation; int old_len = old_list->length(); int new_len = new_list->length(); @@ -1589,7 +1621,8 @@ void LinearScan::sort_intervals_after_allocation() { new_list->sort(interval_cmp); // merge old and new list (both already sorted) into one combined list - IntervalArray* combined_list = new IntervalArray(old_len + new_len); + int combined_list_len = old_len + new_len; + IntervalArray* combined_list = new IntervalArray(combined_list_len, combined_list_len, NULL); int old_idx = 0; int new_idx = 0; @@ -3211,6 +3244,10 @@ void LinearScan::verify_intervals() { has_error = true; } + // special intervals that are created in MoveResolver + // -> ignore them because the range information has no meaning there + if (i1->from() == 1 && i1->to() == 2) continue; + if (i1->first() == Range::end()) { tty->print_cr("Interval %d has no Range", i1->reg_num()); i1->print(); tty->cr(); has_error = true; @@ -3225,18 +3262,13 @@ void LinearScan::verify_intervals() { for (int j = i + 1; j < len; j++) { Interval* i2 = interval_at(j); - if (i2 == NULL) continue; - - // special intervals that are created in MoveResolver - // -> ignore them because the range information has no meaning there - if (i1->from() == 1 && i1->to() == 2) continue; - if (i2->from() == 1 && i2->to() == 2) continue; + if (i2 == NULL || (i2->from() == 1 && i2->to() == 2)) continue; int r1 = i1->assigned_reg(); int r1Hi = i1->assigned_regHi(); int r2 = i2->assigned_reg(); int r2Hi = i2->assigned_regHi(); - if (i1->intersects(i2) && (r1 == r2 || r1 == r2Hi || (r1Hi != any_reg && (r1Hi == r2 || r1Hi == r2Hi)))) { + if ((r1 == r2 || r1 == r2Hi || (r1Hi != any_reg && (r1Hi == r2 || r1Hi == r2Hi))) && i1->intersects(i2)) { tty->print_cr("Intervals %d and %d overlap and have the same register assigned", i1->reg_num(), i2->reg_num()); i1->print(); tty->cr(); i2->print(); tty->cr(); @@ -3429,7 +3461,8 @@ void LinearScan::verify_registers() { void RegisterVerifier::verify(BlockBegin* start) { // setup input registers (method arguments) for first block - IntervalList* input_state = new IntervalList(state_size(), NULL); + int input_state_len = state_size(); + IntervalList* input_state = new IntervalList(input_state_len, input_state_len, NULL); CallingConvention* args = compilation()->frame_map()->incoming_arguments(); for (int n = 0; n < args->length(); n++) { LIR_Opr opr = args->at(n); @@ -3543,7 +3576,7 @@ void RegisterVerifier::process_successor(BlockBegin* block, IntervalList* input_ IntervalList* RegisterVerifier::copy(IntervalList* input_state) { IntervalList* copy_state = new IntervalList(input_state->length()); - copy_state->push_all(input_state); + copy_state->appendAll(input_state); return copy_state; } @@ -5506,7 +5539,7 @@ void LinearScanWalker::split_and_spill_intersecting_intervals(int reg, int regHi IntervalList* processed = _spill_intervals[reg]; for (int i = 0; i < _spill_intervals[regHi]->length(); i++) { Interval* it = _spill_intervals[regHi]->at(i); - if (processed->index_of(it) == -1) { + if (processed->find_from_end(it) == -1) { remove_from_list(it); split_and_spill_interval(it); } diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.hpp b/hotspot/src/share/vm/c1/c1_LinearScan.hpp index 8504cccedcd..7d296e3f674 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.hpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -42,8 +42,8 @@ class LinearScan; class MoveResolver; class Range; -define_array(IntervalArray, Interval*) -define_stack(IntervalList, IntervalArray) +typedef GrowableArray IntervalArray; +typedef GrowableArray IntervalList; define_array(IntervalsArray, IntervalList*) define_stack(IntervalsList, IntervalsArray) From de01af89d88eeb3eb1dfa53e954605057f364d79 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Fri, 19 Feb 2016 11:09:59 +0100 Subject: [PATCH 015/183] 8149655: PPC64: Implement CompactString intrinsics Reviewed-by: goetz, kvn --- hotspot/src/cpu/ppc/vm/globals_ppc.hpp | 7 +- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp | 552 +++++++++++++++ hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp | 38 +- hotspot/src/cpu/ppc/vm/ppc.ad | 632 +++++++++++++++++- hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp | 25 +- hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp | 20 +- hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp | 7 +- .../string/TestStringIntrinsics2.java | 23 + 8 files changed, 1261 insertions(+), 43 deletions(-) diff --git a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp index 695014fd836..d7bb3970582 100644 --- a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 SAP SE. 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 @@ -75,8 +75,7 @@ define_pd_global(size_t, CMSYoungGenPerWorker, 16*M); // Default max size of CM define_pd_global(uintx, TypeProfileLevel, 111); -// No performance work done here yet. -define_pd_global(bool, CompactStrings, false); +define_pd_global(bool, CompactStrings, true); // Platform dependent flag handling: flags only defined on this platform. #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \ diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index e9da9714579..ce9d109dfdd 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -45,6 +45,9 @@ #include "gc/g1/g1SATBCardTableModRefBS.hpp" #include "gc/g1/heapRegion.hpp" #endif // INCLUDE_ALL_GCS +#ifdef COMPILER2 +#include "opto/intrinsicnode.hpp" +#endif #ifdef PRODUCT #define BLOCK_COMMENT(str) // nothing @@ -3168,6 +3171,553 @@ void MacroAssembler::clear_memory_doubleword(Register base_ptr, Register cnt_dwo /////////////////////////////////////////// String intrinsics //////////////////////////////////////////// +#ifdef COMPILER2 +// Intrinsics for CompactStrings + +// Compress char[] to byte[] by compressing 16 bytes at once. +void MacroAssembler::string_compress_16(Register src, Register dst, Register cnt, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, + Label& Lfailure) { + + const Register tmp0 = R0; + assert_different_registers(src, dst, cnt, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5); + Label Lloop, Lslow; + + // Check if cnt >= 8 (= 16 bytes) + lis(tmp1, 0xFF); // tmp1 = 0x00FF00FF00FF00FF + srwi_(tmp2, cnt, 3); + beq(CCR0, Lslow); + ori(tmp1, tmp1, 0xFF); + rldimi(tmp1, tmp1, 32, 0); + mtctr(tmp2); + + // 2x unrolled loop + bind(Lloop); + ld(tmp2, 0, src); // _0_1_2_3 (Big Endian) + ld(tmp4, 8, src); // _4_5_6_7 + + orr(tmp0, tmp2, tmp4); + rldicl(tmp3, tmp2, 6*8, 64-24); // _____1_2 + rldimi(tmp2, tmp2, 2*8, 2*8); // _0_2_3_3 + rldicl(tmp5, tmp4, 6*8, 64-24); // _____5_6 + rldimi(tmp4, tmp4, 2*8, 2*8); // _4_6_7_7 + + andc_(tmp0, tmp0, tmp1); + bne(CCR0, Lfailure); // Not latin1. + addi(src, src, 16); + + rlwimi(tmp3, tmp2, 0*8, 24, 31);// _____1_3 + srdi(tmp2, tmp2, 3*8); // ____0_2_ + rlwimi(tmp5, tmp4, 0*8, 24, 31);// _____5_7 + srdi(tmp4, tmp4, 3*8); // ____4_6_ + + orr(tmp2, tmp2, tmp3); // ____0123 + orr(tmp4, tmp4, tmp5); // ____4567 + + stw(tmp2, 0, dst); + stw(tmp4, 4, dst); + addi(dst, dst, 8); + bdnz(Lloop); + + bind(Lslow); // Fallback to slow version +} + +// Compress char[] to byte[]. cnt must be positive int. +void MacroAssembler::string_compress(Register src, Register dst, Register cnt, Register tmp, Label& Lfailure) { + Label Lloop; + mtctr(cnt); + + bind(Lloop); + lhz(tmp, 0, src); + cmplwi(CCR0, tmp, 0xff); + bgt(CCR0, Lfailure); // Not latin1. + addi(src, src, 2); + stb(tmp, 0, dst); + addi(dst, dst, 1); + bdnz(Lloop); +} + +// Inflate byte[] to char[] by inflating 16 bytes at once. +void MacroAssembler::string_inflate_16(Register src, Register dst, Register cnt, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5) { + const Register tmp0 = R0; + assert_different_registers(src, dst, cnt, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5); + Label Lloop, Lslow; + + // Check if cnt >= 8 + srwi_(tmp2, cnt, 3); + beq(CCR0, Lslow); + lis(tmp1, 0xFF); // tmp1 = 0x00FF00FF + ori(tmp1, tmp1, 0xFF); + mtctr(tmp2); + + // 2x unrolled loop + bind(Lloop); + lwz(tmp2, 0, src); // ____0123 (Big Endian) + lwz(tmp4, 4, src); // ____4567 + addi(src, src, 8); + + rldicl(tmp3, tmp2, 7*8, 64-8); // _______2 + rlwimi(tmp2, tmp2, 3*8, 16, 23);// ____0113 + rldicl(tmp5, tmp4, 7*8, 64-8); // _______6 + rlwimi(tmp4, tmp4, 3*8, 16, 23);// ____4557 + + andc(tmp0, tmp2, tmp1); // ____0_1_ + rlwimi(tmp2, tmp3, 2*8, 0, 23); // _____2_3 + andc(tmp3, tmp4, tmp1); // ____4_5_ + rlwimi(tmp4, tmp5, 2*8, 0, 23); // _____6_7 + + rldimi(tmp2, tmp0, 3*8, 0*8); // _0_1_2_3 + rldimi(tmp4, tmp3, 3*8, 0*8); // _4_5_6_7 + + std(tmp2, 0, dst); + std(tmp4, 8, dst); + addi(dst, dst, 16); + bdnz(Lloop); + + bind(Lslow); // Fallback to slow version +} + +// Inflate byte[] to char[]. cnt must be positive int. +void MacroAssembler::string_inflate(Register src, Register dst, Register cnt, Register tmp) { + Label Lloop; + mtctr(cnt); + + bind(Lloop); + lbz(tmp, 0, src); + addi(src, src, 1); + sth(tmp, 0, dst); + addi(dst, dst, 2); + bdnz(Lloop); +} + +void MacroAssembler::string_compare(Register str1, Register str2, + Register cnt1, Register cnt2, + Register tmp1, Register result, int ae) { + const Register tmp0 = R0, + diff = tmp1; + + assert_different_registers(str1, str2, cnt1, cnt2, tmp0, tmp1, result); + Label Ldone, Lslow, Lloop, Lreturn_diff; + + // Note: Making use of the fact that compareTo(a, b) == -compareTo(b, a) + // we interchange str1 and str2 in the UL case and negate the result. + // Like this, str1 is always latin1 encoded, except for the UU case. + // In addition, we need 0 (or sign which is 0) extend. + + if (ae == StrIntrinsicNode::UU) { + srwi(cnt1, cnt1, 1); + } else { + clrldi(cnt1, cnt1, 32); + } + + if (ae != StrIntrinsicNode::LL) { + srwi(cnt2, cnt2, 1); + } else { + clrldi(cnt2, cnt2, 32); + } + + // See if the lengths are different, and calculate min in cnt1. + // Save diff in case we need it for a tie-breaker. + subf_(diff, cnt2, cnt1); // diff = cnt1 - cnt2 + // if (diff > 0) { cnt1 = cnt2; } + if (VM_Version::has_isel()) { + isel(cnt1, CCR0, Assembler::greater, /*invert*/ false, cnt2); + } else { + Label Lskip; + blt(CCR0, Lskip); + mr(cnt1, cnt2); + bind(Lskip); + } + + // Rename registers + Register chr1 = result; + Register chr2 = tmp0; + + // Compare multiple characters in fast loop (only implemented for same encoding). + int stride1 = 8, stride2 = 8; + if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + int log2_chars_per_iter = (ae == StrIntrinsicNode::LL) ? 3 : 2; + Label Lfastloop, Lskipfast; + + srwi_(tmp0, cnt1, log2_chars_per_iter); + beq(CCR0, Lskipfast); + rldicl(cnt2, cnt1, 0, 64 - log2_chars_per_iter); // Remaining characters. + li(cnt1, 1 << log2_chars_per_iter); // Initialize for failure case: Rescan characters from current iteration. + mtctr(tmp0); + + bind(Lfastloop); + ld(chr1, 0, str1); + ld(chr2, 0, str2); + cmpd(CCR0, chr1, chr2); + bne(CCR0, Lslow); + addi(str1, str1, stride1); + addi(str2, str2, stride2); + bdnz(Lfastloop); + mr(cnt1, cnt2); // Remaining characters. + bind(Lskipfast); + } + + // Loop which searches the first difference character by character. + cmpwi(CCR0, cnt1, 0); + beq(CCR0, Lreturn_diff); + bind(Lslow); + mtctr(cnt1); + + switch (ae) { + case StrIntrinsicNode::LL: stride1 = 1; stride2 = 1; break; + case StrIntrinsicNode::UL: // fallthru (see comment above) + case StrIntrinsicNode::LU: stride1 = 1; stride2 = 2; break; + case StrIntrinsicNode::UU: stride1 = 2; stride2 = 2; break; + default: ShouldNotReachHere(); break; + } + + bind(Lloop); + if (stride1 == 1) { lbz(chr1, 0, str1); } else { lhz(chr1, 0, str1); } + if (stride2 == 1) { lbz(chr2, 0, str2); } else { lhz(chr2, 0, str2); } + subf_(result, chr2, chr1); // result = chr1 - chr2 + bne(CCR0, Ldone); + addi(str1, str1, stride1); + addi(str2, str2, stride2); + bdnz(Lloop); + + // If strings are equal up to min length, return the length difference. + bind(Lreturn_diff); + mr(result, diff); + + // Otherwise, return the difference between the first mismatched chars. + bind(Ldone); + if (ae == StrIntrinsicNode::UL) { + neg(result, result); // Negate result (see note above). + } +} + +void MacroAssembler::array_equals(bool is_array_equ, Register ary1, Register ary2, + Register limit, Register tmp1, Register result, bool is_byte) { + const Register tmp0 = R0; + assert_different_registers(ary1, ary2, limit, tmp0, tmp1, result); + Label Ldone, Lskiploop, Lloop, Lfastloop, Lskipfast; + bool limit_needs_shift = false; + + if (is_array_equ) { + const int length_offset = arrayOopDesc::length_offset_in_bytes(); + const int base_offset = arrayOopDesc::base_offset_in_bytes(is_byte ? T_BYTE : T_CHAR); + + // Return true if the same array. + cmpd(CCR0, ary1, ary2); + beq(CCR0, Lskiploop); + + // Return false if one of them is NULL. + cmpdi(CCR0, ary1, 0); + cmpdi(CCR1, ary2, 0); + li(result, 0); + cror(CCR0, Assembler::equal, CCR1, Assembler::equal); + beq(CCR0, Ldone); + + // Load the lengths of arrays. + lwz(limit, length_offset, ary1); + lwz(tmp0, length_offset, ary2); + + // Return false if the two arrays are not equal length. + cmpw(CCR0, limit, tmp0); + bne(CCR0, Ldone); + + // Load array addresses. + addi(ary1, ary1, base_offset); + addi(ary2, ary2, base_offset); + } else { + limit_needs_shift = !is_byte; + li(result, 0); // Assume not equal. + } + + // Rename registers + Register chr1 = tmp0; + Register chr2 = tmp1; + + // Compare 8 bytes per iteration in fast loop. + const int log2_chars_per_iter = is_byte ? 3 : 2; + + srwi_(tmp0, limit, log2_chars_per_iter + (limit_needs_shift ? 1 : 0)); + beq(CCR0, Lskipfast); + mtctr(tmp0); + + bind(Lfastloop); + ld(chr1, 0, ary1); + ld(chr2, 0, ary2); + addi(ary1, ary1, 8); + addi(ary2, ary2, 8); + cmpd(CCR0, chr1, chr2); + bne(CCR0, Ldone); + bdnz(Lfastloop); + + bind(Lskipfast); + rldicl_(limit, limit, limit_needs_shift ? 64 - 1 : 0, 64 - log2_chars_per_iter); // Remaining characters. + beq(CCR0, Lskiploop); + mtctr(limit); + + // Character by character. + bind(Lloop); + if (is_byte) { + lbz(chr1, 0, ary1); + lbz(chr2, 0, ary2); + addi(ary1, ary1, 1); + addi(ary2, ary2, 1); + } else { + lhz(chr1, 0, ary1); + lhz(chr2, 0, ary2); + addi(ary1, ary1, 2); + addi(ary2, ary2, 2); + } + cmpw(CCR0, chr1, chr2); + bne(CCR0, Ldone); + bdnz(Lloop); + + bind(Lskiploop); + li(result, 1); // All characters are equal. + bind(Ldone); +} + +void MacroAssembler::string_indexof(Register result, Register haystack, Register haycnt, + Register needle, ciTypeArray* needle_values, Register needlecnt, int needlecntval, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, int ae) { + + // Ensure 0=2, bail out otherwise. + // ************************************************************************************************** + + // Compute last haystack addr to use if no match gets found. + clrldi(haycnt, haycnt, 32); // Ensure positive int is valid as 64 bit value. + addi(addr, haystack, -h_csize); // Accesses use pre-increment. + if (needlecntval == 0) { // variable needlecnt + cmpwi(CCR6, needlecnt, 2); + clrldi(needlecnt, needlecnt, 32); // Ensure positive int is valid as 64 bit value. + blt(CCR6, L_TooShort); // Variable needlecnt: handle short needle separately. + } + + if (n_csize == 2) { lwz(n_start, 0, needle); } else { lhz(n_start, 0, needle); } // Load first 2 characters of needle. + + if (needlecntval == 0) { // variable needlecnt + subf(ch1, needlecnt, haycnt); // Last character index to compare is haycnt-needlecnt. + addi(needlecnt, needlecnt, -2); // Rest of needle. + } else { // constant needlecnt + guarantee(needlecntval != 1, "IndexOf with single-character needle must be handled separately"); + assert((needlecntval & 0x7fff) == needlecntval, "wrong immediate"); + addi(ch1, haycnt, -needlecntval); // Last character index to compare is haycnt-needlecnt. + if (needlecntval > 3) { li(needlecnt, needlecntval - 2); } // Rest of needle. + } + + if (h_csize == 2) { slwi(ch1, ch1, 1); } // Scale to number of bytes. + + if (ae ==StrIntrinsicNode::UL) { + srwi(tmp4, n_start, 1*8); // ___0 + rlwimi(n_start, tmp4, 2*8, 0, 23); // _0_1 + } + + add(last_addr, haystack, ch1); // Point to last address to compare (haystack+2*(haycnt-needlecnt)). + + // Main Loop (now we have at least 2 characters). + Label L_OuterLoop, L_InnerLoop, L_FinalCheck, L_Comp1, L_Comp2; + bind(L_OuterLoop); // Search for 1st 2 characters. + Register addr_diff = tmp4; + subf(addr_diff, addr, last_addr); // Difference between already checked address and last address to check. + addi(addr, addr, h_csize); // This is the new address we want to use for comparing. + srdi_(ch2, addr_diff, h_csize); + beq(CCR0, L_FinalCheck); // 2 characters left? + mtctr(ch2); // num of characters / 2 + bind(L_InnerLoop); // Main work horse (2x unrolled search loop) + if (h_csize == 2) { // Load 2 characters of haystack (ignore alignment). + lwz(ch1, 0, addr); + lwz(ch2, 2, addr); + } else { + lhz(ch1, 0, addr); + lhz(ch2, 1, addr); + } + cmpw(CCR0, ch1, n_start); // Compare 2 characters (1 would be sufficient but try to reduce branches to CompLoop). + cmpw(CCR1, ch2, n_start); + beq(CCR0, L_Comp1); // Did we find the needle start? + beq(CCR1, L_Comp2); + addi(addr, addr, 2 * h_csize); + bdnz(L_InnerLoop); + bind(L_FinalCheck); + andi_(addr_diff, addr_diff, h_csize); // Remaining characters not covered by InnerLoop: (num of characters) & 1. + beq(CCR0, L_NotFound); + if (h_csize == 2) { lwz(ch1, 0, addr); } else { lhz(ch1, 0, addr); } // One position left at which we have to compare. + cmpw(CCR1, ch1, n_start); + beq(CCR1, L_Comp1); + bind(L_NotFound); + li(result, -1); // not found + b(L_End); + + // ************************************************************************************************** + // Special Case: unfortunately, the variable needle case can be called with needlecnt<2 + // ************************************************************************************************** + if (needlecntval == 0) { // We have to handle these cases separately. + Label L_OneCharLoop; + bind(L_TooShort); + mtctr(haycnt); + if (n_csize == 2) { lhz(n_start, 0, needle); } else { lbz(n_start, 0, needle); } // First character of needle + bind(L_OneCharLoop); + if (h_csize == 2) { lhzu(ch1, 2, addr); } else { lbzu(ch1, 1, addr); } + cmpw(CCR1, ch1, n_start); + beq(CCR1, L_Found); // Did we find the one character needle? + bdnz(L_OneCharLoop); + li(result, -1); // Not found. + b(L_End); + } + + // ************************************************************************************************** + // Regular Case Part II: compare rest of needle (first 2 characters have been compared already) + // ************************************************************************************************** + + // Compare the rest + bind(L_Comp2); + addi(addr, addr, h_csize); // First comparison has failed, 2nd one hit. + bind(L_Comp1); // Addr points to possible needle start. + if (needlecntval != 2) { // Const needlecnt==2? + if (needlecntval != 3) { + if (needlecntval == 0) { beq(CCR6, L_Found); } // Variable needlecnt==2? + Register n_ind = tmp4, + h_ind = n_ind; + li(n_ind, 2 * n_csize); // First 2 characters are already compared, use index 2. + mtctr(needlecnt); // Decremented by 2, still > 0. + Label L_CompLoop; + bind(L_CompLoop); + if (ae ==StrIntrinsicNode::UL) { + h_ind = ch1; + sldi(h_ind, n_ind, 1); + } + if (n_csize == 2) { lhzx(ch2, needle, n_ind); } else { lbzx(ch2, needle, n_ind); } + if (h_csize == 2) { lhzx(ch1, addr, h_ind); } else { lbzx(ch1, addr, h_ind); } + cmpw(CCR1, ch1, ch2); + bne(CCR1, L_OuterLoop); + addi(n_ind, n_ind, n_csize); + bdnz(L_CompLoop); + } else { // No loop required if there's only one needle character left. + if (n_csize == 2) { lhz(ch2, 2 * 2, needle); } else { lbz(ch2, 2 * 1, needle); } + if (h_csize == 2) { lhz(ch1, 2 * 2, addr); } else { lbz(ch1, 2 * 1, addr); } + cmpw(CCR1, ch1, ch2); + bne(CCR1, L_OuterLoop); + } + } + // Return index ... + bind(L_Found); + subf(result, haystack, addr); // relative to haystack, ... + if (h_csize == 2) { srdi(result, result, 1); } // in characters. + bind(L_End); +} // string_indexof + +void MacroAssembler::string_indexof_char(Register result, Register haystack, Register haycnt, + Register needle, jchar needleChar, Register tmp1, Register tmp2, bool is_byte) { + assert_different_registers(haystack, haycnt, needle, tmp1, tmp2); + + Label L_InnerLoop, L_FinalCheck, L_Found1, L_Found2, L_NotFound, L_End; + Register addr = tmp1, + ch1 = tmp2, + ch2 = R0; + + const int h_csize = is_byte ? 1 : 2; + +//4: + srwi_(tmp2, haycnt, 1); // Shift right by exact_log2(UNROLL_FACTOR). + mr(addr, haystack); + beq(CCR0, L_FinalCheck); + mtctr(tmp2); // Move to count register. +//8: + bind(L_InnerLoop); // Main work horse (2x unrolled search loop). + if (!is_byte) { + lhz(ch1, 0, addr); + lhz(ch2, 2, addr); + } else { + lbz(ch1, 0, addr); + lbz(ch2, 1, addr); + } + (needle != R0) ? cmpw(CCR0, ch1, needle) : cmplwi(CCR0, ch1, (unsigned int)needleChar); + (needle != R0) ? cmpw(CCR1, ch2, needle) : cmplwi(CCR1, ch2, (unsigned int)needleChar); + beq(CCR0, L_Found1); // Did we find the needle? + beq(CCR1, L_Found2); + addi(addr, addr, 2 * h_csize); + bdnz(L_InnerLoop); +//16: + bind(L_FinalCheck); + andi_(R0, haycnt, 1); + beq(CCR0, L_NotFound); + if (!is_byte) { lhz(ch1, 0, addr); } else { lbz(ch1, 0, addr); } // One position left at which we have to compare. + (needle != R0) ? cmpw(CCR1, ch1, needle) : cmplwi(CCR1, ch1, (unsigned int)needleChar); + beq(CCR1, L_Found1); +//21: + bind(L_NotFound); + li(result, -1); // Not found. + b(L_End); + + bind(L_Found2); + addi(addr, addr, h_csize); +//24: + bind(L_Found1); // Return index ... + subf(result, haystack, addr); // relative to haystack, ... + if (!is_byte) { srdi(result, result, 1); } // in characters. + bind(L_End); +} // string_indexof_char + + +void MacroAssembler::has_negatives(Register src, Register cnt, Register result, + Register tmp1, Register tmp2) { + const Register tmp0 = R0; + assert_different_registers(src, result, cnt, tmp0, tmp1, tmp2); + Label Lfastloop, Lslow, Lloop, Lnoneg, Ldone; + + // Check if cnt >= 8 (= 16 bytes) + lis(tmp1, (int)(short)0x8080); // tmp1 = 0x8080808080808080 + srwi_(tmp2, cnt, 4); + li(result, 1); // Assume there's a negative byte. + beq(CCR0, Lslow); + ori(tmp1, tmp1, 0x8080); + rldimi(tmp1, tmp1, 32, 0); + mtctr(tmp2); + + // 2x unrolled loop + bind(Lfastloop); + ld(tmp2, 0, src); + ld(tmp0, 8, src); + + orr(tmp0, tmp2, tmp0); + + and_(tmp0, tmp0, tmp1); + bne(CCR0, Ldone); // Found negative byte. + addi(src, src, 16); + + bdnz(Lfastloop); + + bind(Lslow); // Fallback to slow version + rldicl_(tmp0, cnt, 0, 64-4); + beq(CCR0, Lnoneg); + mtctr(tmp0); + bind(Lloop); + lbz(tmp0, 0, src); + addi(src, src, 1); + andi_(tmp0, tmp0, 0x80); + bne(CCR0, Ldone); // Found negative byte. + bdnz(Lloop); + bind(Lnoneg); + li(result, 0); + + bind(Ldone); +} + + +// Intrinsics for non-CompactStrings + // Search for a single jchar in an jchar[]. // // Assumes that result differs from all other registers. @@ -3613,6 +4163,8 @@ void MacroAssembler::char_arrays_equalsImm(Register str1_reg, Register str2_reg, bind(Ldone_false); } +#endif // Compiler2 + // Helpers for Intrinsic Emitters // // Revert the byte order of a 32bit value in a register diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp index 925e73a82d1..53a269a83c2 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 SAP SE. 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 @@ -679,6 +679,39 @@ class MacroAssembler: public Assembler { void clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp = R0); +#ifdef COMPILER2 + // Intrinsics for CompactStrings + // Compress char[] to byte[] by compressing 16 bytes at once. + void string_compress_16(Register src, Register dst, Register cnt, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, + Label& Lfailure); + + // Compress char[] to byte[]. cnt must be positive int. + void string_compress(Register src, Register dst, Register cnt, Register tmp, Label& Lfailure); + + // Inflate byte[] to char[] by inflating 16 bytes at once. + void string_inflate_16(Register src, Register dst, Register cnt, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5); + + // Inflate byte[] to char[]. cnt must be positive int. + void string_inflate(Register src, Register dst, Register cnt, Register tmp); + + void string_compare(Register str1, Register str2, Register cnt1, Register cnt2, + Register tmp1, Register result, int ae); + + void array_equals(bool is_array_equ, Register ary1, Register ary2, + Register limit, Register tmp1, Register result, bool is_byte); + + void string_indexof(Register result, Register haystack, Register haycnt, + Register needle, ciTypeArray* needle_values, Register needlecnt, int needlecntval, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, int ae); + + void string_indexof_char(Register result, Register haystack, Register haycnt, + Register needle, jchar needleChar, Register tmp1, Register tmp2, bool is_byte); + + void has_negatives(Register src, Register cnt, Register result, Register tmp1, Register tmp2); + + // Intrinsics for non-CompactStrings // Needle of length 1. void string_indexof_1(Register result, Register haystack, Register haycnt, Register needle, jchar needleChar, @@ -694,6 +727,7 @@ class MacroAssembler: public Assembler { Register tmp5_reg); void char_arrays_equalsImm(Register str1_reg, Register str2_reg, int cntval, Register result_reg, Register tmp1_reg, Register tmp2_reg); +#endif // Emitters for BigInteger.multiplyToLen intrinsic. inline void multiply64(Register dest_hi, Register dest_lo, diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index e9dfa9c5bf1..df119f8bdf1 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -1,6 +1,6 @@ // // Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2012, 2015 SAP SE. All rights reserved. +// Copyright (c) 2012, 2016 SAP SE. 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 @@ -2024,13 +2024,13 @@ const bool Matcher::match_rule_supported(int opcode) { return (UsePopCountInstruction && VM_Version::has_popcntw()); case Op_StrComp: - return SpecialStringCompareTo && !CompactStrings; + return SpecialStringCompareTo; case Op_StrEquals: - return SpecialStringEquals && !CompactStrings; + return SpecialStringEquals; case Op_StrIndexOf: - return SpecialStringIndexOf && !CompactStrings; + return SpecialStringIndexOf; case Op_StrIndexOfChar: - return SpecialStringIndexOf && !CompactStrings; + return SpecialStringIndexOf; } return true; // Per default match rules are supported. @@ -11022,6 +11022,584 @@ instruct inlineCallClearArray(rarg1RegL cnt, rarg2RegP base, Universe dummy, reg ins_pipe(pipe_class_default); %} +instruct string_compareL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp); + ins_cost(300); + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + $tmp$$Register, + $result$$Register, StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_compareU(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp); + ins_cost(300); + format %{ "String Compare char[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + $tmp$$Register, + $result$$Register, StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_compareLU(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp); + ins_cost(300); + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + $tmp$$Register, + $result$$Register, StrIntrinsicNode::LU); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_compareUL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp); + ins_cost(300); + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_compare($str2$$Register, $str1$$Register, + $cnt2$$Register, $cnt1$$Register, + $tmp$$Register, + $result$$Register, StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_equalsL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "String Equals byte[] $str1,$str2,$cnt -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ array_equals(false, $str1$$Register, $str2$$Register, + $cnt$$Register, $tmp$$Register, + $result$$Register, true /* byte */); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_equalsU(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "String Equals char[] $str1,$str2,$cnt -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ array_equals(false, $str1$$Register, $str2$$Register, + $cnt$$Register, $tmp$$Register, + $result$$Register, false /* byte */); + %} + ins_pipe(pipe_class_default); +%} + +instruct array_equalsB(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result, + iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR0 cr1) %{ + predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (AryEq ary1 ary2)); + effect(TEMP_DEF result, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0, KILL cr1); + ins_cost(300); + format %{ "Array Equals $ary1,$ary2 -> $result \t// KILL $tmp1,$tmp2" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ array_equals(true, $ary1$$Register, $ary2$$Register, + $tmp1$$Register, $tmp2$$Register, + $result$$Register, true /* byte */); + %} + ins_pipe(pipe_class_default); +%} + +instruct array_equalsC(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result, + iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR0 cr1) %{ + predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (AryEq ary1 ary2)); + effect(TEMP_DEF result, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0, KILL cr1); + ins_cost(300); + format %{ "Array Equals $ary1,$ary2 -> $result \t// KILL $tmp1,$tmp2" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ array_equals(true, $ary1$$Register, $ary2$$Register, + $tmp1$$Register, $tmp2$$Register, + $result$$Register, false /* byte */); + %} + ins_pipe(pipe_class_default); +%} + +instruct indexOf_imm1_char_U(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + immP needleImm, immL offsetImm, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm))); + effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); + ins_cost(150); + + format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]" + "-> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %} + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + immPOper *needleOper = (immPOper *)$needleImm; + const TypeOopPtr *t = needleOper->type()->isa_oopptr(); + ciTypeArray* needle_values = t->const_oop()->as_type_array(); // Pointer to live char * + jchar chr; +#ifdef VM_LITTLE_ENDIAN + chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(0).as_byte()); +#else + chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(1).as_byte()); +#endif + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_char_L(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + immP needleImm, immL offsetImm, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm))); + effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); + ins_cost(150); + + format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]" + "-> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %} + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + immPOper *needleOper = (immPOper *)$needleImm; + const TypeOopPtr *t = needleOper->type()->isa_oopptr(); + ciTypeArray* needle_values = t->const_oop()->as_type_array(); // Pointer to live char * + jchar chr = (jchar)needle_values->element_value(0).as_byte(); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, true /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_char_UL(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + immP needleImm, immL offsetImm, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm))); + effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); + ins_cost(150); + + format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]" + "-> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %} + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + immPOper *needleOper = (immPOper *)$needleImm; + const TypeOopPtr *t = needleOper->type()->isa_oopptr(); + ciTypeArray* needle_values = t->const_oop()->as_type_array(); // Pointer to live char * + jchar chr = (jchar)needle_values->element_value(0).as_byte(); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_U(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + rscratch2RegP needle, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL needle, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(180); + + format %{ "String IndexOf SCL1 $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $needle, $tmp1, $tmp2, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + guarantee(needle_values, "sanity"); + jchar chr; +#ifdef VM_LITTLE_ENDIAN + chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(0).as_byte()); +#else + chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(1).as_byte()); +#endif + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_L(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + rscratch2RegP needle, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL needle, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(180); + + format %{ "String IndexOf SCL1 $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $needle, $tmp1, $tmp2, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + guarantee(needle_values, "sanity"); + jchar chr = (jchar)needle_values->element_value(0).as_byte(); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, true /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_UL(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + rscratch2RegP needle, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL needle, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(180); + + format %{ "String IndexOf SCL1 $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $needle, $tmp1, $tmp2, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + guarantee(needle_values, "sanity"); + jchar chr = (jchar)needle_values->element_value(0).as_byte(); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOfChar_U(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + iRegIsrc ch, iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOfChar (Binary haystack haycnt) ch)); + effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + predicate(CompactStrings); + ins_cost(180); + + format %{ "String IndexOfChar $haystack[0..$haycnt], $ch" + " -> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + $ch$$Register, 0 /* this is not used if the character is already in a register */, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm_U(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, + iRegPsrc needle, uimmI15 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(250); + + format %{ "String IndexOf SCL $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $tmp1, $tmp2, $tmp3, $tmp4, $tmp5, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, needle_values, $tmp5$$Register, $needlecntImm$$constant, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm_L(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, + iRegPsrc needle, uimmI15 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(250); + + format %{ "String IndexOf SCL $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $tmp1, $tmp2, $tmp3, $tmp4, $tmp5, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, needle_values, $tmp5$$Register, $needlecntImm$$constant, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm_UL(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, + iRegPsrc needle, uimmI15 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(250); + + format %{ "String IndexOf SCL $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $tmp1, $tmp2, $tmp3, $tmp4, $tmp5, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, needle_values, $tmp5$$Register, $needlecntImm$$constant, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_U(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRegPsrc needle, rscratch2RegI needlecnt, + iRegLdst tmp1, iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt))); + effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/ + TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); + ins_cost(300); + + format %{ "String IndexOf $haystack[0..$haycnt], $needle[0..$needlecnt]" + " -> $result \t// KILL $haycnt, $needlecnt, $tmp1, $tmp2, $tmp3, $tmp4, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant. + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_L(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRegPsrc needle, rscratch2RegI needlecnt, + iRegLdst tmp1, iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt))); + effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/ + TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); + ins_cost(300); + + format %{ "String IndexOf $haystack[0..$haycnt], $needle[0..$needlecnt]" + " -> $result \t// KILL $haycnt, $needlecnt, $tmp1, $tmp2, $tmp3, $tmp4, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant. + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_UL(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRegPsrc needle, rscratch2RegI needlecnt, + iRegLdst tmp1, iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt))); + effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/ + TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); + ins_cost(300); + + format %{ "String IndexOf $haystack[0..$haycnt], $needle[0..$needlecnt]" + " -> $result \t// KILL $haycnt, $needlecnt, $tmp1, $tmp2, $tmp3, $tmp4, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant. + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_compare); +%} + +// char[] to byte[] compression +instruct string_compress(rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegIdst result, iRegLdst tmp1, + iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{ + match(Set result (StrCompressedCopy src (Binary dst len))); + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, + USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "String Compress $src,$dst,$len -> $result \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Label Lskip, Ldone; + __ li($result$$Register, 0); + __ string_compress_16($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register, + $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, Ldone); + __ rldicl_($tmp1$$Register, $len$$Register, 0, 64-3); // Remaining characters. + __ beq(CCR0, Lskip); + __ string_compress($src$$Register, $dst$$Register, $tmp1$$Register, $tmp2$$Register, Ldone); + __ bind(Lskip); + __ mr($result$$Register, $len$$Register); + __ bind(Ldone); + %} + ins_pipe(pipe_class_default); +%} + +// byte[] to char[] inflation +instruct string_inflate(Universe dummy, rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegLdst tmp1, + iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{ + match(Set dummy (StrInflatedCopy src (Binary dst len))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "String Inflate $src,$dst,$len \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Label Ldone; + __ string_inflate_16($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register, + $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register); + __ rldicl_($tmp1$$Register, $len$$Register, 0, 64-3); // Remaining characters. + __ beq(CCR0, Ldone); + __ string_inflate($src$$Register, $dst$$Register, $tmp1$$Register, $tmp2$$Register); + __ bind(Ldone); + %} + ins_pipe(pipe_class_default); +%} + +// StringCoding.java intrinsics +instruct has_negatives(rarg1RegP ary1, iRegIsrc len, iRegIdst result, iRegLdst tmp1, iRegLdst tmp2, + regCTR ctr, flagsRegCR0 cr0) +%{ + match(Set result (HasNegatives ary1 len)); + effect(TEMP_DEF result, USE_KILL ary1, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "has negatives byte[] $ary1,$len -> $result \t// KILL $tmp1, $tmp2" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ has_negatives($ary1$$Register, $len$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register); + %} + ins_pipe(pipe_class_default); +%} + +// encode char[] to byte[] in ISO_8859_1 +instruct encode_iso_array(rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegIdst result, iRegLdst tmp1, + iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{ + match(Set result (EncodeISOArray src (Binary dst len))); + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, + USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "Encode array $src,$dst,$len -> $result \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Label Lslow, Lfailure1, Lfailure2, Ldone; + __ string_compress_16($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register, + $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, Lfailure1); + __ rldicl_($result$$Register, $len$$Register, 0, 64-3); // Remaining characters. + __ beq(CCR0, Ldone); + __ bind(Lslow); + __ string_compress($src$$Register, $dst$$Register, $result$$Register, $tmp2$$Register, Lfailure2); + __ li($result$$Register, 0); + __ b(Ldone); + + __ bind(Lfailure1); + __ mr($result$$Register, $len$$Register); + __ mfctr($tmp1$$Register); + __ rldimi_($result$$Register, $tmp1$$Register, 3, 0); // Remaining characters. + __ beq(CCR0, Ldone); + __ b(Lslow); + + __ bind(Lfailure2); + __ mfctr($result$$Register); // Remaining characters. + + __ bind(Ldone); + __ subf($result$$Register, $result$$Register, $len$$Register); + %} + ins_pipe(pipe_class_default); +%} + + // String_IndexOf for needle of length 1. // // Match needle into immediate operands: no loadConP node needed. Saves one @@ -11060,11 +11638,11 @@ instruct string_indexOf_imm1_char(iRegIdst result, iRegPsrc haystack, iRegIsrc h if (java_lang_String::has_coder_field()) { // New compact strings byte array strings #ifdef VM_LITTLE_ENDIAN - chr = (((jchar)needle_values->element_value(1).as_byte()) << 8) | - (jchar)needle_values->element_value(0).as_byte(); + chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(0).as_byte()); #else - chr = (((jchar)needle_values->element_value(0).as_byte()) << 8) | - (jchar)needle_values->element_value(1).as_byte(); + chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(1).as_byte()); #endif } else { // Old char array strings @@ -11115,11 +11693,11 @@ instruct string_indexOf_imm1(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt if (java_lang_String::has_coder_field()) { // New compact strings byte array strings #ifdef VM_LITTLE_ENDIAN - chr = (((jchar)needle_values->element_value(1).as_byte()) << 8) | - (jchar)needle_values->element_value(0).as_byte(); + chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(0).as_byte()); #else - chr = (((jchar)needle_values->element_value(0).as_byte()) << 8) | - (jchar)needle_values->element_value(1).as_byte(); + chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(1).as_byte()); #endif } else { // Old char array strings @@ -11321,6 +11899,20 @@ instruct minI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{ %} %} +instruct minI_reg_reg_isel(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ + match(Set dst (MinI src1 src2)); + effect(KILL cr0); + predicate(VM_Version::has_isel()); + ins_cost(DEFAULT_COST*2); + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ cmpw(CCR0, $src1$$Register, $src2$$Register); + __ isel($dst$$Register, CCR0, Assembler::less, /*invert*/false, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_class_default); +%} + instruct maxI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{ match(Set dst (MaxI src1 src2)); ins_cost(DEFAULT_COST*6); @@ -11341,6 +11933,20 @@ instruct maxI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{ %} %} +instruct maxI_reg_reg_isel(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ + match(Set dst (MaxI src1 src2)); + effect(KILL cr0); + predicate(VM_Version::has_isel()); + ins_cost(DEFAULT_COST*2); + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ cmpw(CCR0, $src1$$Register, $src2$$Register); + __ isel($dst$$Register, CCR0, Assembler::greater, /*invert*/false, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_class_default); +%} + //---------- Population Count Instructions ------------------------------------ // Popcnt for Power7. diff --git a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp index c3f6922fe2d..85a83c8179b 100644 --- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp @@ -2609,9 +2609,7 @@ class StubGenerator: public StubCodeGenerator { * R5_ARG3 - int length (of buffer) * * scratch: - * R6_ARG4 - crc table address - * R7_ARG5 - tmp1 - * R8_ARG6 - tmp2 + * R2, R6-R12 * * Ouput: * R3_RET - int crc result @@ -2623,22 +2621,25 @@ class StubGenerator: public StubCodeGenerator { address start = __ function_entry(); // Remember stub start address (is rtn value). // arguments to kernel_crc32: - Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call. - Register data = R4_ARG2; // source byte array - Register dataLen = R5_ARG3; // #bytes to process - Register table = R6_ARG4; // crc table address + const Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call. + const Register data = R4_ARG2; // source byte array + const Register dataLen = R5_ARG3; // #bytes to process + const Register table = R6_ARG4; // crc table address - Register t0 = R9; // work reg for kernel* emitters - Register t1 = R10; // work reg for kernel* emitters - Register t2 = R11; // work reg for kernel* emitters - Register t3 = R12; // work reg for kernel* emitters + const Register t0 = R2; + const Register t1 = R7; + const Register t2 = R8; + const Register t3 = R9; + const Register tc0 = R10; + const Register tc1 = R11; + const Register tc2 = R12; BLOCK_COMMENT("Stub body {"); assert_different_registers(crc, data, dataLen, table); StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table); - __ kernel_crc32_1byte(crc, data, dataLen, table, t0, t1, t2, t3); + __ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, table); BLOCK_COMMENT("return"); __ mr_if_needed(R3_RET, crc); // Updated crc is function result. No copying required (R3_ARG1 == R3_RET). diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index 51bc85d869d..63c0e30a913 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 SAP SE. 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 @@ -53,7 +53,7 @@ void VM_Version::initialize() { // If PowerArchitecturePPC64 hasn't been specified explicitly determine from features. if (FLAG_IS_DEFAULT(PowerArchitecturePPC64)) { - if (VM_Version::has_tcheck() && VM_Version::has_lqarx()) { + if (VM_Version::has_lqarx()) { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 8); } else if (VM_Version::has_popcntw()) { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 7); @@ -68,8 +68,7 @@ void VM_Version::initialize() { bool PowerArchitecturePPC64_ok = false; switch (PowerArchitecturePPC64) { - case 8: if (!VM_Version::has_tcheck() ) break; - if (!VM_Version::has_lqarx() ) break; + case 8: if (!VM_Version::has_lqarx() ) break; case 7: if (!VM_Version::has_popcntw()) break; case 6: if (!VM_Version::has_cmpb() ) break; case 5: if (!VM_Version::has_popcntb()) break; @@ -80,7 +79,7 @@ void VM_Version::initialize() { UINTX_FORMAT " on this machine", PowerArchitecturePPC64); // Power 8: Configure Data Stream Control Register. - if (PowerArchitecturePPC64 >= 8) { + if (has_mfdscr()) { config_dscr(); } @@ -112,7 +111,7 @@ void VM_Version::initialize() { // Create and print feature-string. char buf[(num_features+1) * 16]; // Max 16 chars per feature. jio_snprintf(buf, sizeof(buf), - "ppc64%s%s%s%s%s%s%s%s%s%s%s%s", + "ppc64%s%s%s%s%s%s%s%s%s%s%s%s%s", (has_fsqrt() ? " fsqrt" : ""), (has_isel() ? " isel" : ""), (has_lxarxeh() ? " lxarxeh" : ""), @@ -125,7 +124,8 @@ void VM_Version::initialize() { (has_lqarx() ? " lqarx" : ""), (has_vcipher() ? " vcipher" : ""), (has_vpmsumb() ? " vpmsumb" : ""), - (has_tcheck() ? " tcheck" : "") + (has_tcheck() ? " tcheck" : ""), + (has_mfdscr() ? " mfdscr" : "") // Make sure number of %s matches num_features! ); _features_string = os::strdup(buf); @@ -610,6 +610,7 @@ void VM_Version::determine_features() { a->vcipher(VR0, VR1, VR2); // code[10] -> vcipher a->vpmsumb(VR0, VR1, VR2); // code[11] -> vpmsumb a->tcheck(0); // code[12] -> tcheck + a->mfdscr(R0); // code[13] -> mfdscr a->blr(); // Emit function to set one cache line to zero. Emit function descriptor and get pointer to it. @@ -657,6 +658,7 @@ void VM_Version::determine_features() { if (code[feature_cntr++]) features |= vcipher_m; if (code[feature_cntr++]) features |= vpmsumb_m; if (code[feature_cntr++]) features |= tcheck_m; + if (code[feature_cntr++]) features |= mfdscr_m; // Print the detection code. if (PrintAssembly) { @@ -670,8 +672,6 @@ void VM_Version::determine_features() { // Power 8: Configure Data Stream Control Register. void VM_Version::config_dscr() { - assert(has_tcheck(), "Only execute on Power 8 or later!"); - // 7 InstWords for each call (function descriptor + blr instruction). const int code_size = (2+2*7)*BytesPerInstWord; diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp index 46fdd6b6470..fccb4e21874 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 SAP SE. 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 @@ -45,6 +45,7 @@ protected: vcipher, vpmsumb, tcheck, + mfdscr, num_features // last entry to count features }; enum Feature_Flag_Set { @@ -62,6 +63,7 @@ protected: vcipher_m = (1 << vcipher), vpmsumb_m = (1 << vpmsumb), tcheck_m = (1 << tcheck ), + mfdscr_m = (1 << mfdscr ), all_features_m = (unsigned long)-1 }; @@ -94,6 +96,7 @@ public: static bool has_vcipher() { return (_features & vcipher_m) != 0; } static bool has_vpmsumb() { return (_features & vpmsumb_m) != 0; } static bool has_tcheck() { return (_features & tcheck_m) != 0; } + static bool has_mfdscr() { return (_features & mfdscr_m) != 0; } // Assembler testing static void allow_all(); diff --git a/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java b/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java index a59e412bc96..7bba5308971 100644 --- a/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java +++ b/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java @@ -494,6 +494,29 @@ public class TestStringIntrinsics2 { return s.indexOf("1"); } + static String text1UTF16 = "A" + "\u05d0" + "\u05d1" + "B"; + + @Test(role = Role.TEST_ENTRY) + public static void test_indexOf_immUTF16() { + assertEquals( 3, indexOf_imm1Latin1_needle(text1UTF16), "test_indexOf_immUTF16"); + assertEquals( 1, indexOf_imm1UTF16_needle(text1UTF16), "test_indexOf_immUTF16"); + assertEquals( 1, indexOf_immUTF16_needle(text1UTF16), "test_indexOf_immUTF16"); + } + + @Test(role = Role.TEST_HELPER, compileAt = 4, warmup = 1, warmupArgs = { "A" + "\u05d0" + "\u05d1" + "B" }) + static int indexOf_imm1Latin1_needle(String s) { + return s.indexOf("B"); + } + + @Test(role = Role.TEST_HELPER, compileAt = 4, warmup = 1, warmupArgs = { "A" + "\u05d0" + "\u05d1" + "B" }) + static int indexOf_imm1UTF16_needle(String s) { + return s.indexOf("\u05d0"); + } + + @Test(role = Role.TEST_HELPER, compileAt = 4, warmup = 1, warmupArgs = { "A" + "\u05d0" + "\u05d1" + "B" }) + static int indexOf_immUTF16_needle(String s) { + return s.indexOf("\u05d0" + "\u05d1"); + } @Test(role = Role.TEST_HELPER, compileAt = 4, warmup = 1, warmupArgs = { "abc", "abcd" }) public static int asmStringCompareTo(String a, String b) { From 30e4522d2fef451699796ab994681a0e3ca9c0ad Mon Sep 17 00:00:00 2001 From: Konstantin Shefov Date: Sat, 20 Feb 2016 11:44:14 +0300 Subject: [PATCH 016/183] 8141616: Add new methods to the java Whitebox API Reviewed-by: kvn, dpochepk --- hotspot/src/share/vm/prims/whitebox.cpp | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 51750b8338e..407d7249125 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -34,6 +34,7 @@ #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" #include "memory/universe.hpp" +#include "oops/constantPool.hpp" #include "oops/oop.inline.hpp" #include "prims/wbtestmethods/parserTests.hpp" #include "prims/whitebox.hpp" @@ -1305,6 +1306,38 @@ WB_ENTRY(jlong, WB_GetConstantPool(JNIEnv* env, jobject wb, jclass klass)) return (jlong) ikh->constants(); WB_END +WB_ENTRY(jint, WB_GetConstantPoolCacheIndexTag(JNIEnv* env, jobject wb)) + return ConstantPool::CPCACHE_INDEX_TAG; +WB_END + +WB_ENTRY(jint, WB_GetConstantPoolCacheLength(JNIEnv* env, jobject wb, jclass klass)) + instanceKlassHandle ikh(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + ConstantPool* cp = ikh->constants(); + if (cp->cache() == NULL) { + return -1; + } + return cp->cache()->length(); +WB_END + +WB_ENTRY(jint, WB_ConstantPoolRemapInstructionOperandFromCache(JNIEnv* env, jobject wb, jclass klass, jint index)) + instanceKlassHandle ikh(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + ConstantPool* cp = ikh->constants(); + if (cp->cache() == NULL) { + THROW_MSG_0(vmSymbols::java_lang_IllegalStateException(), "Constant pool does not have a cache"); + } + jint cpci = index; + jint cpciTag = ConstantPool::CPCACHE_INDEX_TAG; + if (cpciTag > cpci || cpci >= cp->cache()->length() + cpciTag) { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Constant pool cache index is out of range"); + } + jint cpi = cp->remap_instruction_operand_from_cache(cpci); + return cpi; +WB_END + +WB_ENTRY(jint, WB_ConstantPoolEncodeIndyIndex(JNIEnv* env, jobject wb, jint index)) + return ConstantPool::encode_invokedynamic_index(index); +WB_END + WB_ENTRY(void, WB_ClearInlineCaches(JNIEnv* env, jobject wb)) VM_ClearICs clear_ics; VMThread::execute(&clear_ics); @@ -1620,6 +1653,12 @@ static JNINativeMethod methods[] = { {CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint }, {CC"getConstantPool0", CC"(Ljava/lang/Class;)J", (void*)&WB_GetConstantPool }, + {CC"getConstantPoolCacheIndexTag0", CC"()I", (void*)&WB_GetConstantPoolCacheIndexTag}, + {CC"getConstantPoolCacheLength0", CC"(Ljava/lang/Class;)I", (void*)&WB_GetConstantPoolCacheLength}, + {CC"remapInstructionOperandFromCPCache0", + CC"(Ljava/lang/Class;I)I", (void*)&WB_ConstantPoolRemapInstructionOperandFromCache}, + {CC"encodeConstantPoolIndyIndex0", + CC"(I)I", (void*)&WB_ConstantPoolEncodeIndyIndex}, {CC"getMethodBooleanOption", CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)Ljava/lang/Boolean;", (void*)&WB_GetMethodBooleaneOption}, From ac6fe07b0509bd72b2821b9b8926dfc3759e4100 Mon Sep 17 00:00:00 2001 From: Konstantin Shefov Date: Sat, 20 Feb 2016 11:49:02 +0300 Subject: [PATCH 017/183] 8141618: Change JVMCI compilerToVM constant pool tests to support CP cache Reviewed-by: twisti, dpochepk --- .../MultipleAbstractImplementer.java | 82 ++- .../testcases/MultipleImplementer2.java | 68 ++- .../MultipleImplementersInterface.java | 33 +- .../compilerToVM/ConstantPoolTestCase.java | 282 ++++++---- .../compilerToVM/ConstantPoolTestsHelper.java | 504 +++++++++++++++--- .../compilerToVM/LookupKlassInPoolTest.java | 75 +-- .../ResolveConstantInPoolTest.java | 88 +-- .../compilerToVM/ResolveTypeInPoolTest.java | 64 ++- 8 files changed, 920 insertions(+), 276 deletions(-) diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java index d90b5285c02..3e090394bbc 100644 --- a/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,93 @@ package compiler.jvmci.common.testcases; +import java.util.HashMap; +import java.util.Map; + public abstract class MultipleAbstractImplementer implements MultipleImplementersInterface { + // Different access levels on the fields of this class are used on purpose. + // It is needed to verify jdk.vm.ci.CompilerToVM constant pool related + // methods, e.g. resolveFieldInPool. + + private static int intStaticField = INT_CONSTANT; + final static long longStaticField = LONG_CONSTANT; + volatile static float floatStaticField = FLOAT_CONSTANT; + static double doubleStaticField = DOUBLE_CONSTANT; + public static String stringStaticField = STRING_CONSTANT; + protected static Object objectStaticField = OBJECT_CONSTANT; + + public int intField = INT_CONSTANT; + private long longField = LONG_CONSTANT; + protected float floatField = FLOAT_CONSTANT; + transient double doubleField = DOUBLE_CONSTANT; + volatile String stringField = STRING_CONSTANT; + String stringFieldEmpty = ""; + final Object objectField; + + public MultipleAbstractImplementer() { + intField = Integer.MAX_VALUE; + longField = Long.MAX_VALUE; + floatField = Float.MAX_VALUE; + doubleField = Double.MAX_VALUE; + stringField = "Message"; + objectField = new Object(); + } + public abstract void abstractMethod(); @Override public void finalize() throws Throwable { super.finalize(); } + + public void lambdaUsingMethod2() { + Thread t = new Thread(this::testMethod); + t.start(); + } + + /** + * This method is needed to have "getstatic" and "getfield" instructions + * in the class. These instructions are needed to test + * resolveFieldInPool method, because it needs a bytecode as one of its arguments. + */ + public void printFileds() { + System.out.println(intStaticField); + System.out.println(longStaticField); + System.out.println(floatStaticField); + System.out.println(doubleStaticField); + System.out.println(stringStaticField); + System.out.println(objectStaticField); + System.out.println(intField); + System.out.println(longField); + System.out.println(floatField); + System.out.println(doubleField); + System.out.println(stringField); + System.out.println(stringFieldEmpty); + System.out.println(objectField); + } + + public static void staticMethod() { + System.getProperties(); // calling some static method + Map map = new HashMap(); // calling some constructor + map.put(OBJECT_CONSTANT, OBJECT_CONSTANT); // calling some interface method + map.remove(OBJECT_CONSTANT); // calling some default interface method + } + + @Override + public void instanceMethod() { + toString(); // calling some virtual method + super.toString(); // calling some special method + } + + @Override + public void anonClassMethod() { + new Runnable() { + @Override + public void run() { + System.out.println("Running"); + } + }.run(); + } } diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java index 274df6b5c0f..e7a7b3cc0c3 100644 --- a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,18 @@ package compiler.jvmci.common.testcases; +import java.util.HashMap; +import java.util.Map; + public class MultipleImplementer2 implements MultipleImplementersInterface { + // Different access levels on the fields of this class are used on purpose. + // It is needed to verify jdk.vm.ci.CompilerToVM constant pool related + // methods, e.g. resolveFieldInPool. + private static int intStaticField = INT_CONSTANT; - static long longStaticField = LONG_CONSTANT; - static float floatStaticField = FLOAT_CONSTANT; + final static long longStaticField = LONG_CONSTANT; + volatile static float floatStaticField = FLOAT_CONSTANT; static double doubleStaticField = DOUBLE_CONSTANT; public static String stringStaticField = STRING_CONSTANT; protected static Object objectStaticField = OBJECT_CONSTANT; @@ -35,9 +42,10 @@ public class MultipleImplementer2 implements MultipleImplementersInterface { public int intField = INT_CONSTANT; private long longField = LONG_CONSTANT; protected float floatField = FLOAT_CONSTANT; - double doubleField = DOUBLE_CONSTANT; - String stringField = STRING_CONSTANT; - Object objectField = OBJECT_CONSTANT; + transient double doubleField = DOUBLE_CONSTANT; + volatile String stringField = STRING_CONSTANT; + String stringFieldEmpty = ""; + final Object objectField; public MultipleImplementer2() { intField = Integer.MAX_VALUE; @@ -58,12 +66,52 @@ public class MultipleImplementer2 implements MultipleImplementersInterface { super.finalize(); } - public void interfaceMethodReferral2(MultipleImplementersInterface obj) { - obj.interfaceMethodReferral(obj); - } - public void lambdaUsingMethod2() { Thread t = new Thread(this::testMethod); t.start(); } + + /** + * This method is needed to have "getstatic" and "getfield" instructions + * in the class. These instructions are needed to test + * resolveFieldInPool method, because it needs a bytecode as one of its arguments. + */ + public void printFileds() { + System.out.println(intStaticField); + System.out.println(longStaticField); + System.out.println(floatStaticField); + System.out.println(doubleStaticField); + System.out.println(stringStaticField); + System.out.println(objectStaticField); + System.out.println(intField); + System.out.println(longField); + System.out.println(floatField); + System.out.println(doubleField); + System.out.println(stringField); + System.out.println(stringFieldEmpty); + System.out.println(objectField); + } + + public static void staticMethod() { + System.getProperties(); // calling some static method + Map map = new HashMap(); // calling some constructor + map.put(OBJECT_CONSTANT, OBJECT_CONSTANT); // calling some interface method + map.remove(OBJECT_CONSTANT); // calling some default interface method + } + + @Override + public void instanceMethod() { + toString(); // calling some virtual method + super.toString(); // calling some special method + } + + @Override + public void anonClassMethod() { + new Runnable() { + @Override + public void run() { + System.out.println("Running"); + } + }.run(); + } } diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java index 9ce4e792bc6..5257e592c6e 100644 --- a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java @@ -23,6 +23,9 @@ package compiler.jvmci.common.testcases; +import java.util.HashMap; +import java.util.Map; + public interface MultipleImplementersInterface { int INT_CONSTANT = Integer.MAX_VALUE; @@ -42,12 +45,34 @@ public interface MultipleImplementersInterface { // empty } - default void interfaceMethodReferral(MultipleImplementersInterface obj) { - obj.defaultMethod(); - } - default void lambdaUsingMethod() { Thread t = new Thread(this::defaultMethod); t.start(); } + + default void printFields() { + System.out.println(OBJECT_CONSTANT); + String s = ""; + System.out.println(s); + } + + static void staticMethod() { + System.getProperties(); // calling some static method + Map map = new HashMap(); // calling some constructor + map.put(OBJECT_CONSTANT, OBJECT_CONSTANT); // calling some interface method + map.remove(OBJECT_CONSTANT); // calling some default interface method + } + + default void instanceMethod() { + toString(); // calling some virtual method + } + + default void anonClassMethod() { + new Runnable() { + @Override + public void run() { + System.out.println("Running"); + } + }.run(); + } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java index b9716cca2a2..df4046d889f 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -27,118 +27,214 @@ package compiler.jvmci.compilerToVM; import java.util.HashMap; import java.util.Map; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import jdk.internal.misc.SharedSecrets; +import sun.hotspot.WhiteBox; import sun.reflect.ConstantPool; +import sun.reflect.ConstantPool.Tag; +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; /** * Common class for jdk.vm.ci.hotspot.CompilerToVM constant pool tests */ public class ConstantPoolTestCase { - private final Map typeTests; + + private static final Map TAG_TO_TYPE_MAP; + static { + TAG_TO_TYPE_MAP = new HashMap<>(); + TAG_TO_TYPE_MAP.put(Tag.CLASS, CONSTANT_CLASS); + TAG_TO_TYPE_MAP.put(Tag.FIELDREF, CONSTANT_FIELDREF); + TAG_TO_TYPE_MAP.put(Tag.METHODREF, CONSTANT_METHODREF); + TAG_TO_TYPE_MAP.put(Tag.INTERFACEMETHODREF, CONSTANT_INTERFACEMETHODREF); + TAG_TO_TYPE_MAP.put(Tag.STRING, CONSTANT_STRING); + TAG_TO_TYPE_MAP.put(Tag.INTEGER, CONSTANT_INTEGER); + TAG_TO_TYPE_MAP.put(Tag.FLOAT, CONSTANT_FLOAT); + TAG_TO_TYPE_MAP.put(Tag.LONG, CONSTANT_LONG); + TAG_TO_TYPE_MAP.put(Tag.DOUBLE, CONSTANT_DOUBLE); + TAG_TO_TYPE_MAP.put(Tag.NAMEANDTYPE, CONSTANT_NAMEANDTYPE); + TAG_TO_TYPE_MAP.put(Tag.UTF8, CONSTANT_UTF8); + TAG_TO_TYPE_MAP.put(Tag.METHODHANDLE, CONSTANT_METHODHANDLE); + TAG_TO_TYPE_MAP.put(Tag.METHODTYPE, CONSTANT_METHODTYPE); + TAG_TO_TYPE_MAP.put(Tag.INVOKEDYNAMIC, CONSTANT_INVOKEDYNAMIC); + TAG_TO_TYPE_MAP.put(Tag.INVALID, CONSTANT_INVALID); + } + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private final Map typeTests; + + public static enum ConstantTypes { + CONSTANT_CLASS { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + checkIndex(constantPoolSS, index); + Class klass = constantPoolSS.getClassAt(index); + String klassName = klass.getName(); + TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this); + for (TestedCPEntry entry : testedEntries) { + if (entry.klass.replaceAll("/", "\\.").equals(klassName)) { + return entry; + } + } + return null; + } + }, + CONSTANT_FIELDREF { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + return this.getTestedCPEntryForMethodAndField(dummyClass, index); + } + }, + CONSTANT_METHODREF { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + return this.getTestedCPEntryForMethodAndField(dummyClass, index); + } + }, + CONSTANT_INTERFACEMETHODREF { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + return this.getTestedCPEntryForMethodAndField(dummyClass, index); + } + }, + CONSTANT_STRING { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + checkIndex(constantPoolSS, index); + String value = constantPoolSS.getStringAt(index); + TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this); + for (TestedCPEntry entry : testedEntries) { + if (entry.name.equals(value)) { + return entry; + } + } + return null; + } + }, + CONSTANT_INTEGER, + CONSTANT_FLOAT, + CONSTANT_LONG, + CONSTANT_DOUBLE, + CONSTANT_NAMEANDTYPE, + CONSTANT_UTF8, + CONSTANT_METHODHANDLE, + CONSTANT_METHODTYPE, + CONSTANT_INVOKEDYNAMIC { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + checkIndex(constantPoolSS, index); + int nameAndTypeIndex = constantPoolSS.getNameAndTypeRefIndexAt(index); + String[] info = constantPoolSS.getNameAndTypeRefInfoAt(nameAndTypeIndex); + TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this); + for (TestedCPEntry entry : testedEntries) { + if (info[0].equals(entry.name) && info[1].equals(entry.type)) { + return entry; + } + } + return null; + } + }, + CONSTANT_INVALID; + + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + return null; // returning null by default + } + + public TestedCPEntry[] getAllCPEntriesForType(DummyClasses dummyClass) { + TestedCPEntry[] toReturn = dummyClass.testedCP.get(this); + if (toReturn == null) { + return new TestedCPEntry[0]; + } + return dummyClass.testedCP.get(this); + } + + protected TestedCPEntry getTestedCPEntryForMethodAndField(DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + checkIndex(constantPoolSS, index); + String[] info = constantPoolSS.getMemberRefInfoAt(index); + TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this); + for (TestedCPEntry entry : testedEntries) { + if (info[0].equals(entry.klass) && info[1].equals(entry.name) && info[2].equals(entry.type)) { + return entry; + } + } + return null; + } + + protected void checkIndex(ConstantPool constantPoolSS, int index) { + ConstantPool.Tag tag = constantPoolSS.getTagAt(index); + ConstantTypes type = mapTagToCPType(tag); + if (!this.equals(type)) { + String msg = String.format("TESTBUG: CP tag should be a %s, but is %s", + this.name(), + type.name()); + throw new Error(msg); + } + } + } public static interface Validator { void validate(jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int index); + ConstantTypes cpType, + DummyClasses dummyClass, + int index); } - public ConstantPoolTestCase(Map typeTests) { + public static class TestedCPEntry { + public final String klass; + public final String name; + public final String type; + public final byte[] opcodes; + public final long accFlags; + + public TestedCPEntry(String klass, String name, String type, byte[] opcodes, long accFlags) { + this.klass = klass; + this.name = name; + this.type = type; + if (opcodes != null) { + this.opcodes = new byte[opcodes.length]; + System.arraycopy(opcodes, 0, this.opcodes, 0, opcodes.length); + } else { + this.opcodes = null; + } + this.accFlags = accFlags; + } + + public TestedCPEntry(String klass, String name, String type, byte[] opcodes) { + this(klass, name, type, opcodes, 0); + } + + public TestedCPEntry(String klass, String name, String type) { + this(klass, name, type, null, 0); + } + } + + public static ConstantTypes mapTagToCPType(Tag tag) { + return TAG_TO_TYPE_MAP.get(tag); + } + + public ConstantPoolTestCase(Map typeTests) { this.typeTests = new HashMap<>(); this.typeTests.putAll(typeTests); } - private void messageOnFail(Throwable t, - ConstantPoolTestsHelper.ConstantTypes cpType, - ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { - ConstantPool constantPoolSS = SharedSecrets.getJavaLangAccess(). - getConstantPool(dummyClass.klass); - String msg = String.format("Test for %s constant pool entry of" - + " type %s", - dummyClass.klass, cpType.name()); - switch (cpType) { - case CONSTANT_CLASS: - case CONSTANT_STRING: - case CONSTANT_METHODTYPE: - String utf8 = constantPoolSS - .getUTF8At((int) dummyClass.cp.get(index).value); - msg = String.format("%s (%s) failed with %s", msg, utf8, t); - break; - case CONSTANT_INTEGER: - int intValue = constantPoolSS.getIntAt(index); - msg = String.format("%s (%d) failed with %s", msg, intValue, t); - break; - case CONSTANT_LONG: - long longValue = constantPoolSS.getLongAt(index); - msg = String.format("%s (%d) failed with %s", msg, longValue, t); - break; - case CONSTANT_FLOAT: - float floatValue = constantPoolSS.getFloatAt(index); - msg = String.format("%s (%E) failed with %s", msg, floatValue, t); - break; - case CONSTANT_DOUBLE: - double doubleValue = constantPoolSS.getDoubleAt(index); - msg = String.format("%s (%E) failed with %s", msg, doubleValue, t); - break; - case CONSTANT_UTF8: - String utf8Value = constantPoolSS.getUTF8At(index); - msg = String.format("%s (%s) failed with %s", msg, utf8Value, t); - break; - case CONSTANT_INVOKEDYNAMIC: - index = ((int[]) dummyClass.cp.get(index).value)[1]; - case CONSTANT_NAMEANDTYPE: - String name = constantPoolSS - .getUTF8At(((int[]) dummyClass.cp.get(index).value)[0]); - String type = constantPoolSS - .getUTF8At(((int[]) dummyClass.cp.get(index).value)[1]); - msg = String.format("%s (%s:%s) failed with %s", - msg, name, type, t); - break; - case CONSTANT_METHODHANDLE: - index = ((int[]) dummyClass.cp.get(index).value)[1]; - case CONSTANT_METHODREF: - case CONSTANT_INTERFACEMETHODREF: - case CONSTANT_FIELDREF: - int classIndex = ((int[]) dummyClass.cp.get(index).value)[0]; - int nameAndTypeIndex = ((int[]) dummyClass.cp.get(index).value)[1]; - String cName = constantPoolSS - .getUTF8At((int) dummyClass.cp.get(classIndex).value); - String mName = constantPoolSS - .getUTF8At(((int[]) dummyClass.cp.get(nameAndTypeIndex).value)[0]); - String mType = constantPoolSS - .getUTF8At(((int[]) dummyClass.cp.get(nameAndTypeIndex).value)[1]); - msg = String.format("%s (%s.%s:%s) failed with %s ", - msg, cName, mName, mType, t); - break; - default: - msg = String.format("Test bug: unknown constant type %s ", cpType); - } - throw new Error(msg + t.getMessage(), t); - } - public void test() { - for (ConstantPoolTestsHelper.DummyClasses dummyClass - : ConstantPoolTestsHelper.DummyClasses.values()) { - System.out.printf("%nTesting dummy %s%n", dummyClass.klass); - HotSpotResolvedObjectType holder = HotSpotResolvedObjectType - .fromObjectClass(dummyClass.klass); - jdk.vm.ci.meta.ConstantPool constantPoolCTVM - = holder.getConstantPool(); - ConstantPool constantPoolSS = SharedSecrets.getJavaLangAccess(). - getConstantPool(dummyClass.klass); - for (Integer i : dummyClass.cp.keySet()) { - ConstantPoolTestsHelper.ConstantTypes cpType - = dummyClass.cp.get(i).type; + for (DummyClasses dummyClass : DummyClasses.values()) { + boolean isCPCached = WB.getConstantPoolCacheLength(dummyClass.klass) > -1; + System.out.printf("Testing dummy %s with constant pool cached = %b%n", + dummyClass.klass, + isCPCached); + HotSpotResolvedObjectType holder = HotSpotResolvedObjectType.fromObjectClass(dummyClass.klass); + jdk.vm.ci.meta.ConstantPool constantPoolCTVM = holder.getConstantPool(); + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + for (int i = 0; i < constantPoolSS.getSize(); i++) { + Tag tag = constantPoolSS.getTagAt(i); + ConstantTypes cpType = mapTagToCPType(tag); if (!typeTests.keySet().contains(cpType)) { continue; } - try { - typeTests.get(cpType).validate(constantPoolCTVM, - constantPoolSS, dummyClass, i); - } catch (Throwable t) { - messageOnFail(t, cpType, dummyClass, i); - } + typeTests.get(cpType).validate(constantPoolCTVM, cpType, dummyClass, i); } } } } - diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java index 777b848fd8b..783b26188e9 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,19 @@ */ package compiler.jvmci.compilerToVM; +import compiler.jvmci.common.testcases.MultipleAbstractImplementer; import compiler.jvmci.common.testcases.MultipleImplementer2; import compiler.jvmci.common.testcases.MultipleImplementersInterface; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; import java.util.HashMap; import java.util.Map; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.org.objectweb.asm.Opcodes; +import sun.hotspot.WhiteBox; +import sun.reflect.ConstantPool; +import sun.reflect.ConstantPool.Tag; /** * Class contains hard-coded constant pool tables for dummy classes used for @@ -34,104 +43,437 @@ import java.util.Map; */ public class ConstantPoolTestsHelper { - public enum ConstantTypes { - CONSTANT_CLASS, - CONSTANT_FIELDREF, - CONSTANT_METHODREF, - CONSTANT_INTERFACEMETHODREF, - CONSTANT_STRING, - CONSTANT_INTEGER, - CONSTANT_FLOAT, - CONSTANT_LONG, - CONSTANT_DOUBLE, - CONSTANT_NAMEANDTYPE, - CONSTANT_UTF8, - CONSTANT_METHODHANDLE, - CONSTANT_METHODTYPE, - CONSTANT_INVOKEDYNAMIC; - } + public static final int NO_CP_CACHE_PRESENT = Integer.MAX_VALUE; public enum DummyClasses { DUMMY_CLASS(MultipleImplementer2.class, CP_MAP_FOR_CLASS), + DUMMY_ABS_CLASS(MultipleAbstractImplementer.class, CP_MAP_FOR_ABS_CLASS), DUMMY_INTERFACE(MultipleImplementersInterface.class, CP_MAP_FOR_INTERFACE); + private static final WhiteBox WB = WhiteBox.getWhiteBox(); public final Class klass; - public final Map cp; + public final ConstantPool constantPoolSS; + public final Map testedCP; - DummyClasses(Class klass, Map cp) { + DummyClasses(Class klass, Map testedCP) { this.klass = klass; - this.cp = cp; + this.constantPoolSS = SharedSecrets.getJavaLangAccess().getConstantPool(klass); + this.testedCP = testedCP; + } + + public int getCPCacheIndex(int cpi) { + int cacheLength = WB.getConstantPoolCacheLength(this.klass); + int indexTag = WB.getConstantPoolCacheIndexTag(); + for (int cpci = indexTag; cpci < cacheLength + indexTag; cpci++) { + if (WB.remapInstructionOperandFromCPCache(this.klass, cpci) == cpi) { + if (constantPoolSS.getTagAt(cpi).equals(Tag.INVOKEDYNAMIC)) { + return WB.encodeConstantPoolIndyIndex(cpci) + indexTag; + } + return cpci; + } + } + return NO_CP_CACHE_PRESENT; } } - public static class ConstantPoolEntry { - - public final ConstantTypes type; - public final Object value; - - public ConstantPoolEntry(ConstantTypes type, Object value) { - this.type = type; - this.value = value; - } + private static final Map CP_MAP_FOR_CLASS = new HashMap<>(); + static { + CP_MAP_FOR_CLASS.put(CONSTANT_CLASS, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2$1", null, null), + new TestedCPEntry("java/lang/invoke/MethodHandles$Lookup", null, null), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_FIELDREF, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "intStaticField", + "I", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "longStaticField", + "J", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_FINAL | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "floatStaticField", + "F", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_VOLATILE | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "doubleStaticField", + "D", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "stringStaticField", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "objectStaticField", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "intField", + "I", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PUBLIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "longField", + "J", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PRIVATE), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "floatField", + "F", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PROTECTED), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "doubleField", + "D", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_TRANSIENT), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "objectField", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_FINAL), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "stringField", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_VOLATILE), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "stringFieldEmpty", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + 0L), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_METHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/System", + "getProperties", + "()Ljava/util/Properties;", + new byte[] {(byte) Opcodes.INVOKESTATIC}), + new TestedCPEntry("java/util/HashMap", + "", + "()V", + new byte[] {(byte) Opcodes.INVOKESPECIAL}), + new TestedCPEntry("java/lang/Object", + "toString", + "()Ljava/lang/String;", + new byte[] {(byte) Opcodes.INVOKESPECIAL, + (byte) Opcodes.INVOKEVIRTUAL}), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2$1", + "", + "(Lcompiler/jvmci/common/testcases/MultipleImplementer2;)V", + new byte[0]), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "run", + "()V", + new byte[0]), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_INTERFACEMETHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/util/Map", + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + new TestedCPEntry("java/util/Map", + "remove", + "(Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_STRING, + new TestedCPEntry[] { + new TestedCPEntry(null, "Message", null), + new TestedCPEntry(null, "", null), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_METHODHANDLE, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;" + + "Ljava/lang/String;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodHandle;" + + "Ljava/lang/invoke/MethodType;)" + + "Ljava/lang/invoke/CallSite;", + null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "testMethod", + "()V"), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_METHODTYPE, + new TestedCPEntry[] { + new TestedCPEntry(null, null, "()V"), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_INVOKEDYNAMIC, + new TestedCPEntry[] { + new TestedCPEntry(null, + "run", + "(Lcompiler/jvmci/common/testcases/MultipleImplementer2;)" + + "Ljava/lang/Runnable;"), + } + ); } - private static final Map CP_MAP_FOR_CLASS + private static final Map CP_MAP_FOR_ABS_CLASS = new HashMap<>(); static { - CP_MAP_FOR_CLASS.put(1, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{22, 68})); - CP_MAP_FOR_CLASS.put(2, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 69)); - CP_MAP_FOR_CLASS.put(3, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTEGER, 2147483647)); - CP_MAP_FOR_CLASS.put(4, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{35, 70})); - CP_MAP_FOR_CLASS.put(5, new ConstantPoolEntry(ConstantTypes.CONSTANT_LONG, 9223372036854775807L)); - CP_MAP_FOR_CLASS.put(8, new ConstantPoolEntry(ConstantTypes.CONSTANT_FLOAT, 3.4028235E38F)); - CP_MAP_FOR_CLASS.put(10, new ConstantPoolEntry(ConstantTypes.CONSTANT_DOUBLE, 1.7976931348623157E308D)); - CP_MAP_FOR_CLASS.put(13, new ConstantPoolEntry(ConstantTypes.CONSTANT_STRING, 74)); - CP_MAP_FOR_CLASS.put(22, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 83)); - CP_MAP_FOR_CLASS.put(23, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{22, 84})); - CP_MAP_FOR_CLASS.put(24, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTERFACEMETHODREF, new int[]{2, 85})); - CP_MAP_FOR_CLASS.put(26, new ConstantPoolEntry(ConstantTypes.CONSTANT_INVOKEDYNAMIC, new int[]{0, 91})); - CP_MAP_FOR_CLASS.put(29, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{35, 94})); - CP_MAP_FOR_CLASS.put(35, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 100)); - CP_MAP_FOR_CLASS.put(68, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{54, 55})); - CP_MAP_FOR_CLASS.put(70, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{48, 37})); - CP_MAP_FOR_CLASS.put(84, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{59, 55})); - CP_MAP_FOR_CLASS.put(85, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{103, 63})); - CP_MAP_FOR_CLASS.put(91, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{106, 107})); - CP_MAP_FOR_CLASS.put(94, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{36, 37})); - CP_MAP_FOR_CLASS.put(104, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{110, 111})); - CP_MAP_FOR_CLASS.put(105, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{35, 112})); - CP_MAP_FOR_CLASS.put(110, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 113)); - CP_MAP_FOR_CLASS.put(111, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{114, 118})); - CP_MAP_FOR_CLASS.put(112, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{58, 55})); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_CLASS, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", null, null), + new TestedCPEntry("java/lang/invoke/MethodHandles$Lookup", null, null), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_FIELDREF, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "intStaticField", + "I", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "longStaticField", + "J", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_FINAL | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "floatStaticField", + "F", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_VOLATILE | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "doubleStaticField", + "D", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "stringStaticField", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "objectStaticField", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "intField", + "I", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PUBLIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "longField", + "J", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PRIVATE), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "floatField", + "F", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PROTECTED), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "doubleField", + "D", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_TRANSIENT), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "objectField", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_FINAL), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "stringField", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_VOLATILE), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "stringFieldEmpty", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + 0L), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_METHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/System", + "getProperties", + "()Ljava/util/Properties;", + new byte[] {(byte) Opcodes.INVOKESTATIC}), + new TestedCPEntry("java/util/HashMap", + "", + "()V", + new byte[] {(byte) Opcodes.INVOKESPECIAL}), + new TestedCPEntry("java/lang/Object", + "toString", + "()Ljava/lang/String;", + new byte[] {(byte) Opcodes.INVOKESPECIAL, + (byte) Opcodes.INVOKEVIRTUAL}), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "", + "(Lcompiler/jvmci/common/testcases/MultipleAbstractImplementer;)V", + new byte[0]), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "run", + "()V", + new byte[0]), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_INTERFACEMETHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/util/Map", + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + new TestedCPEntry("java/util/Map", + "remove", + "(Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_STRING, + new TestedCPEntry[] { + new TestedCPEntry(null, "Message", null), + new TestedCPEntry(null, "", null), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_METHODHANDLE, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;" + + "Ljava/lang/String;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodHandle;" + + "Ljava/lang/invoke/MethodType;)" + + "Ljava/lang/invoke/CallSite;", + null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "testMethod", + "()V"), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_METHODTYPE, + new TestedCPEntry[] { + new TestedCPEntry(null, null, "()V"), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_INVOKEDYNAMIC, + new TestedCPEntry[] { + new TestedCPEntry(null, + "run", + "(Lcompiler/jvmci/common/testcases/MultipleAbstractImplementer;)" + + "Ljava/lang/Runnable;"), + } + ); } - private static final Map CP_MAP_FOR_INTERFACE + private static final Map CP_MAP_FOR_INTERFACE = new HashMap<>(); static { - CP_MAP_FOR_INTERFACE.put(1, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 48)); - CP_MAP_FOR_INTERFACE.put(5, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTERFACEMETHODREF, new int[]{13, 52})); - CP_MAP_FOR_INTERFACE.put(6, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 53)); - CP_MAP_FOR_INTERFACE.put(7, new ConstantPoolEntry(ConstantTypes.CONSTANT_INVOKEDYNAMIC, new int[]{0, 58})); - CP_MAP_FOR_INTERFACE.put(8, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{6, 59})); - CP_MAP_FOR_INTERFACE.put(9, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{6, 60})); - CP_MAP_FOR_INTERFACE.put(12, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{13, 63})); - CP_MAP_FOR_INTERFACE.put(13, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 64)); - CP_MAP_FOR_INTERFACE.put(17, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTEGER, 2147483647)); - CP_MAP_FOR_INTERFACE.put(20, new ConstantPoolEntry(ConstantTypes.CONSTANT_LONG, 9223372036854775807l)); - CP_MAP_FOR_INTERFACE.put(24, new ConstantPoolEntry(ConstantTypes.CONSTANT_FLOAT, 3.4028235E38f)); - CP_MAP_FOR_INTERFACE.put(27, new ConstantPoolEntry(ConstantTypes.CONSTANT_DOUBLE, 1.7976931348623157E308d)); - CP_MAP_FOR_INTERFACE.put(31, new ConstantPoolEntry(ConstantTypes.CONSTANT_STRING, 65)); - CP_MAP_FOR_INTERFACE.put(52, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{34, 35})); - CP_MAP_FOR_INTERFACE.put(55, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODHANDLE, new int[]{6, 67})); - CP_MAP_FOR_INTERFACE.put(56, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODTYPE, 35)); - CP_MAP_FOR_INTERFACE.put(57, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODHANDLE, new int[]{9, 5})); - CP_MAP_FOR_INTERFACE.put(58, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{68, 69})); - CP_MAP_FOR_INTERFACE.put(59, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{70, 71})); - CP_MAP_FOR_INTERFACE.put(60, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{72, 35})); - CP_MAP_FOR_INTERFACE.put(63, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{32, 33})); - CP_MAP_FOR_INTERFACE.put(67, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{73, 74})); - CP_MAP_FOR_INTERFACE.put(73, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 75)); - CP_MAP_FOR_INTERFACE.put(74, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{76, 80})); - CP_MAP_FOR_INTERFACE.put(77, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 82)); + CP_MAP_FOR_INTERFACE.put(CONSTANT_CLASS, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface$1", null, null), + new TestedCPEntry("java/lang/Object", null, null), + new TestedCPEntry("java/lang/invoke/MethodHandles$Lookup", null, null), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_FIELDREF, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", + "OBJECT_CONSTANT", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_METHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/System", + "getProperties", + "()Ljava/util/Properties;", + new byte[] {(byte) Opcodes.INVOKESTATIC}), + new TestedCPEntry("java/util/HashMap", + "", + "()V", + new byte[] {(byte) Opcodes.INVOKESPECIAL}), + new TestedCPEntry("java/lang/Object", + "toString", + "()Ljava/lang/String;", + new byte[] {(byte) Opcodes.INVOKEVIRTUAL}), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "", + "(Lcompiler/jvmci/common/testcases/MultipleAbstractImplementer;)V", + new byte[0]), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "run", + "()V", + new byte[0]), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_INTERFACEMETHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/util/Map", + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + new TestedCPEntry("java/util/Map", + "remove", + "(Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_STRING, + new TestedCPEntry[] { + new TestedCPEntry(null, "Hello", null), + new TestedCPEntry(null, "", null), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_METHODHANDLE, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;" + + "Ljava/lang/String;Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodHandle;" + + "Ljava/lang/invoke/MethodType;)" + + "Ljava/lang/invoke/CallSite;"), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", + "defaultMethod", + "()V"), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_METHODTYPE, + new TestedCPEntry[] { + new TestedCPEntry(null, null, "()V"), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_INVOKEDYNAMIC, + new TestedCPEntry[] { + new TestedCPEntry(null, + "run", + "(Lcompiler/jvmci/common/testcases/MultipleImplementersInterface;)" + + "Ljava/lang/Runnable;"), + } + ); } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java index b3fb21028af..09893c05008 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -29,58 +29,73 @@ * @summary Testing compiler.jvmci.CompilerToVM.lookupKlassInPool method * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java - * @build compiler.jvmci.common.testcases.MultipleImplementersInterface - * compiler.jvmci.common.testcases.MultipleImplementer2 - * compiler.jvmci.compilerToVM.ConstantPoolTestsHelper - * compiler.jvmci.compilerToVM.ConstantPoolTestCase + * @build sun.hotspot.WhiteBox * compiler.jvmci.compilerToVM.LookupKlassInPoolTest - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.LookupKlassInPoolTest */ package compiler.jvmci.compilerToVM; +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; import java.util.HashMap; import java.util.Map; import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import sun.reflect.ConstantPool; +import jdk.vm.ci.meta.ConstantPool; /** - * Test for {@code compiler.jvmci.CompilerToVM.lookupKlassInPool} method + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupKlassInPool} method */ public class LookupKlassInPoolTest { - public static void main(String[] args) { - Map typeTests = new HashMap<>(1); - typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_CLASS, - LookupKlassInPoolTest::validate); + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_CLASS, LookupKlassInPoolTest::validate); ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); } - public static void validate(jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int i) { - Object classToVerify = CompilerToVMHelper - .lookupKlassInPool(constantPoolCTVM, i); - if (!(classToVerify instanceof HotSpotResolvedObjectType) - && !(classToVerify instanceof String)) { - String msg = String.format("Output of method" - + " CTVM.lookupKlassInPool is neither" - + " a HotSpotResolvedObjectType, nor a String"); + public static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int i) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, i); + if (entry == null) { + return; + } + Object classToVerify = CompilerToVMHelper.lookupKlassInPool(constantPoolCTVM, i); + if (!(classToVerify instanceof HotSpotResolvedObjectType) && !(classToVerify instanceof String)) { + String msg = String.format("Output of method CTVM.lookupKlassInPool is neither" + + " a HotSpotResolvedObjectType, nor a String"); throw new AssertionError(msg); } - int classNameIndex = (int) dummyClass.cp.get(i).value; - String classNameToRefer - = constantPoolSS.getUTF8At(classNameIndex); + String classNameToRefer = entry.klass; String outputToVerify = classToVerify.toString(); if (!outputToVerify.contains(classNameToRefer)) { - String msg = String.format("Wrong class accessed by constant" - + " pool index %d: %s, but should be %s", - i, outputToVerify, classNameToRefer); + String msg = String.format("Wrong class accessed by constant pool index %d: %s, but should be %s", + i, + outputToVerify, + classNameToRefer); throw new AssertionError(msg); } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java index e72240e0316..2c37309923d 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -28,66 +28,86 @@ * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java - * @build compiler.jvmci.compilerToVM.ResolveConstantInPoolTest - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.ResolveConstantInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI * compiler.jvmci.compilerToVM.ResolveConstantInPoolTest */ package compiler.jvmci.compilerToVM; +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.util.HashMap; import java.util.Map; -import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.test.lib.Asserts; -import sun.reflect.ConstantPool; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; /** - * Test for {@code compiler.jvmci.CompilerToVM.resolveConstantInPool} method + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.resolveConstantInPool} method */ public class ResolveConstantInPoolTest { + private static final String NOT_NULL_MSG + = "Object returned by resolveConstantInPool method should not be null"; + public static void main(String[] args) throws Exception { - Map typeTests = new HashMap<>(2); - typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_METHODHANDLE, - ResolveConstantInPoolTest::validateMethodHandle); - typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_METHODTYPE, - ResolveConstantInPoolTest::validateMethodType); + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODHANDLE, ResolveConstantInPoolTest::validateMethodHandle); + typeTests.put(CONSTANT_METHODTYPE, ResolveConstantInPoolTest::validateMethodType); ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); } - private static void validateMethodHandle( - jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { - Object constantInPool = CompilerToVMHelper - .resolveConstantInPool(constantPoolCTVM, index); + private static void validateMethodHandle(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int index) { + Object constantInPool = CompilerToVMHelper.resolveConstantInPool(constantPoolCTVM, index); + String msg = String.format("%s for index %d", NOT_NULL_MSG, index); + Asserts.assertNotNull(constantInPool, msg); if (!(constantInPool instanceof MethodHandle)) { - String msg = String.format( - "Wrong constant pool entry accessed by index" - + " %d: %s, but should be subclass of %s", - index + 1, constantInPool.getClass(), - MethodHandle.class.getName()); + msg = String.format("Wrong constant pool entry accessed by index" + + " %d: %s, but should be subclass of %s", + index, + constantInPool.getClass(), + MethodHandle.class.getName()); throw new AssertionError(msg); } } - private static void validateMethodType( - jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { - Object constantInPool = CompilerToVMHelper - .resolveConstantInPool(constantPoolCTVM, index); + private static void validateMethodType(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int index) { + Object constantInPool = CompilerToVMHelper.resolveConstantInPool(constantPoolCTVM, index); + String msg = String.format("%s for index %d", NOT_NULL_MSG, index); + Asserts.assertNotNull(constantInPool, msg); Class mtToVerify = constantInPool.getClass(); Class mtToRefer = MethodType.class; - String msg = String.format("Wrong %s accessed by constant pool index" - + " %d: %s, but should be %s", "method type class", - index, mtToVerify, mtToRefer); + msg = String.format("Wrong method type class accessed by" + + " constant pool index %d", + index); Asserts.assertEQ(mtToRefer, mtToVerify, msg); } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java index 9b205e347ad..1e5fe57f369 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -29,51 +29,69 @@ * @summary Testing compiler.jvmci.CompilerToVM.resolveTypeInPool method * @library /testlibrary /test/lib / * @compile ../common/CompilerToVMHelper.java - * @build compiler.jvmci.common.testcases.MultipleImplementersInterface - * compiler.jvmci.common.testcases.MultipleImplementer2 - * compiler.jvmci.compilerToVM.ConstantPoolTestsHelper - * compiler.jvmci.compilerToVM.ConstantPoolTestCase + * @build sun.hotspot.WhiteBox * compiler.jvmci.compilerToVM.ResolveTypeInPoolTest - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.ResolveTypeInPoolTest */ package compiler.jvmci.compilerToVM; +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; import java.util.HashMap; import java.util.Map; import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import sun.reflect.ConstantPool; +import jdk.vm.ci.meta.ConstantPool; /** - * Test for {@code compiler.jvmci.CompilerToVM.resolveTypeInPool} method + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.resolveTypeInPool} method */ public class ResolveTypeInPoolTest { public static void main(String[] args) throws Exception { - Map typeTests = new HashMap<>(1); - typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_CLASS, - ResolveTypeInPoolTest::validate); + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_CLASS, ResolveTypeInPoolTest::validate); ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); } - public static void validate( - jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int i) { - HotSpotResolvedObjectType typeToVerify = CompilerToVMHelper - .resolveTypeInPool(constantPoolCTVM, i); - int classNameIndex = (int) dummyClass.cp.get(i).value; - String classNameToRefer = constantPoolSS.getUTF8At(classNameIndex); + public static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int i) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, i); + if (entry == null) { + return; + } + HotSpotResolvedObjectType typeToVerify = CompilerToVMHelper.resolveTypeInPool(constantPoolCTVM, i); + String classNameToRefer = entry.klass; String outputToVerify = typeToVerify.toString(); if (!outputToVerify.contains(classNameToRefer)) { String msg = String.format("Wrong class accessed by constant" - + " pool index %d: %s, but should be %s", - i, outputToVerify, classNameToRefer); + + " pool index %d: %s, but should be %s", + i, + outputToVerify, + classNameToRefer); throw new AssertionError(msg); } } From 719c07ec100c07433f22a887670f657abf705841 Mon Sep 17 00:00:00 2001 From: Konstantin Shefov Date: Sat, 20 Feb 2016 11:49:45 +0300 Subject: [PATCH 018/183] 8141619: Develop new tests for JVMCI compilerToVM class' CP related methods Reviewed-by: twisti, dpochepk --- .../LookupKlassRefIndexInPoolTest.java | 102 +++++++++++ .../compilerToVM/LookupMethodInPoolTest.java | 120 +++++++++++++ .../LookupNameAndTypeRefIndexInPoolTest.java | 103 ++++++++++++ .../compilerToVM/LookupNameInPoolTest.java | 100 +++++++++++ .../LookupSignatureInPoolTest.java | 102 +++++++++++ .../compilerToVM/ResolveFieldInPoolTest.java | 159 ++++++++++++++++++ ...solvePossiblyCachedConstantInPoolTest.java | 96 +++++++++++ 7 files changed, 782 insertions(+) create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java create mode 100644 hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java new file mode 100644 index 00000000000..e1dbe9f9494 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupKlassRefIndexInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupKlassRefIndexInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupKlassRefIndexInPool} method + */ +public class LookupKlassRefIndexInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupKlassRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupKlassRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_FIELDREF, LookupKlassRefIndexInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + int indexToVerify = CompilerToVMHelper.lookupKlassRefIndexInPool(constantPoolCTVM, index); + int indexToRefer = dummyClass.constantPoolSS.getClassRefIndexAt(cpi); + String msg = String.format("Wrong class index returned by lookupKlassRefIndexInPool method " + + "applied to %sconstant pool index %d", + cached, + index); + Asserts.assertEQ(indexToRefer, indexToVerify, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java new file mode 100644 index 00000000000..a1e71bb2b3a --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupMethodInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupMethodInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupMethodInPool} method + */ +public class LookupMethodInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupMethodInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupMethodInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + for (int j = 0; j < entry.opcodes.length; j++) { + HotSpotResolvedJavaMethod methodToVerify = CompilerToVMHelper + .lookupMethodInPool(constantPoolCTVM, index, entry.opcodes[j]); + String msg = String.format("Object returned by lookupMethodInPool method" + + " for %sindex %d should not be null", + cached, + index); + Asserts.assertNotNull(methodToVerify, msg); + String[] classNameSplit = entry.klass.split("/"); + String classNameToRefer = classNameSplit[classNameSplit.length - 1]; + String methodNameToRefer = entry.name; + String methodToVerifyToString = methodToVerify.toString(); + if (!methodToVerifyToString.contains(classNameToRefer) + || !methodToVerifyToString.contains(methodNameToRefer)) { + msg = String.format("String representation \"%s\" of the object" + + " returned by lookupMethodInPool method" + + " for index %d does not contain a method's class name" + + " or method's name, should contain %s.%s", + methodToVerifyToString, + index, + classNameToRefer, + methodNameToRefer); + throw new AssertionError(msg); + } + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java new file mode 100644 index 00000000000..0eea14aa8d4 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupNameAndTypeRefIndexInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupNameAndTypeRefIndexInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupNameAndTypeRefIndexInPool} method + */ +public class LookupNameAndTypeRefIndexInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupNameAndTypeRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupNameAndTypeRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_FIELDREF, LookupNameAndTypeRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_INVOKEDYNAMIC, LookupNameAndTypeRefIndexInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + int indexToVerify = CompilerToVMHelper.lookupNameAndTypeRefIndexInPool(constantPoolCTVM, index); + int indexToRefer = dummyClass.constantPoolSS.getNameAndTypeRefIndexAt(cpi); + String msg = String.format("Wrong nameAndType index returned by lookupNameAndTypeRefIndexInPool" + + " method applied to %sconstant pool index %d", + cached, + index); + Asserts.assertEQ(indexToRefer, indexToVerify, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java new file mode 100644 index 00000000000..09db06c8a77 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupNameInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupNameInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; +import jdk.test.lib.Asserts; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupNameInPool} method + */ +public class LookupNameInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupNameInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupNameInPoolTest::validate); + typeTests.put(CONSTANT_FIELDREF, LookupNameInPoolTest::validate); + typeTests.put(CONSTANT_INVOKEDYNAMIC, LookupNameInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + String nameToVerify = CompilerToVMHelper.lookupNameInPool(constantPoolCTVM, index); + String nameToRefer = entry.name; + String msg = String.format("Wrong name accessed by %sconstant pool index %d", cached, index); + Asserts.assertEQ(nameToVerify, nameToRefer, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java new file mode 100644 index 00000000000..00f55833891 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupSignatureInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupSignatureInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupSignatureInPool} method + */ +public class LookupSignatureInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupSignatureInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupSignatureInPoolTest::validate); + typeTests.put(CONSTANT_FIELDREF, LookupSignatureInPoolTest::validate); + typeTests.put(CONSTANT_INVOKEDYNAMIC, LookupSignatureInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + String sigToVerify = CompilerToVMHelper.lookupSignatureInPool(constantPoolCTVM, index); + String sigToRefer = entry.type; + String msg = String.format("Wrong signature accessed by %sconstant pool index %d", + cached, + index); + Asserts.assertEQ(sigToVerify, sigToRefer, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java new file mode 100644 index 00000000000..9e99842110f --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.ResolveFieldInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.ResolveFieldInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.ConstantPool; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.misc.Unsafe; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.resolveFieldInPool} method + */ +public class ResolveFieldInPoolTest { + + private static final Unsafe UNSAFE = Utils.getUnsafe(); + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_FIELDREF, ResolveFieldInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + for (int j = 0; j < entry.opcodes.length; j++) { + long[] info = new long[2]; + HotSpotResolvedObjectType fieldToVerify + = CompilerToVMHelper.resolveFieldInPool(constantPoolCTVM, + index, + entry.opcodes[j], + info); + String msg = String.format("Object returned by resolveFieldInPool method" + + " for %sindex %d should not be null", + cached, + index); + Asserts.assertNotNull(fieldToVerify, msg); + String classNameToRefer = entry.klass; + String fieldToVerifyKlassToString = fieldToVerify.klass().toValueString(); + if (!fieldToVerifyKlassToString.contains(classNameToRefer)) { + msg = String.format("String representation \"%s\" of the object" + + " returned by resolveFieldInPool method" + + " for index %d does not contain a field's class name," + + " should contain %s", + fieldToVerifyKlassToString, + index, + classNameToRefer); + throw new AssertionError(msg); + } + msg = String.format("Access flags returned by resolveFieldInPool" + + " method are wrong for the field %s.%s" + + " at %sindex %d", + entry.klass, + entry.name, + cached, + index); + Asserts.assertEQ(info[0], entry.accFlags, msg); + if (cpci == -1) { + return; + } + Class classOfTheField = null; + Field fieldToRefer = null; + try { + classOfTheField = Class.forName(classNameToRefer.replaceAll("/", "\\.")); + fieldToRefer = classOfTheField.getDeclaredField(entry.name); + fieldToRefer.setAccessible(true); + } catch (Exception ex) { + throw new Error("Unexpected exception", ex); + } + long offsetToRefer; + if ((entry.accFlags & Opcodes.ACC_STATIC) != 0) { + offsetToRefer = UNSAFE.staticFieldOffset(fieldToRefer); + } else { + offsetToRefer = UNSAFE.objectFieldOffset(fieldToRefer); + } + msg = String.format("Field offset returned by resolveFieldInPool" + + " method is wrong for the field %s.%s" + + " at %sindex %d", + entry.klass, + entry.name, + cached, + index); + Asserts.assertEQ(info[1], offsetToRefer, msg); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java new file mode 100644 index 00000000000..6f0af4c2ce1 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @compile ../common/CompilerToVMHelper.java + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.ResolvePossiblyCachedConstantInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.ResolvePossiblyCachedConstantInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.resolvePossiblyCachedConstantInPool} method + */ +public class ResolvePossiblyCachedConstantInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_STRING, ResolvePossiblyCachedConstantInPoolTest::validateString); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + // The next "Class.forName" is here for the following reason. + // When class is initialized, constant pool cache is available. + // This method works only with cached constant pool. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validateString(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + Object constantInPool = CompilerToVMHelper.resolvePossiblyCachedConstantInPool(constantPoolCTVM, index); + String stringToVerify = (String) constantInPool; + String stringToRefer = entry.name; + if (stringToRefer.equals("") && cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + stringToRefer = null; // tested method returns null for cached empty strings + } + String msg = String.format("Wrong string accessed by %sconstant pool index %d", cached, index); + Asserts.assertEQ(stringToRefer, stringToVerify, msg); + } +} From 78d37841efc43504081d6a439b99a4aa0fda84b9 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Mon, 15 Feb 2016 10:14:33 +0100 Subject: [PATCH 019/183] 8087341: C2 doesn't optimize redundant memory operations with G1 Effect of memory barrier in post barrier is too wide Reviewed-by: kvn, aph --- hotspot/src/cpu/aarch64/vm/aarch64.ad | 1162 +++++++++++------------- hotspot/src/share/vm/opto/graphKit.cpp | 18 +- hotspot/src/share/vm/opto/graphKit.hpp | 1 + 3 files changed, 533 insertions(+), 648 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index e94d23c150e..18ba1e44cf3 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -1041,10 +1041,8 @@ class HandlerImpl { bool is_card_mark_membar(const MemBarNode *barrier); bool is_CAS(int opcode); - MemBarNode *leading_to_normal(MemBarNode *leading); - MemBarNode *normal_to_leading(const MemBarNode *barrier); - MemBarNode *card_mark_to_trailing(const MemBarNode *barrier); - MemBarNode *trailing_to_card_mark(const MemBarNode *trailing); + MemBarNode *leading_to_trailing(MemBarNode *leading); + MemBarNode *card_mark_to_leading(const MemBarNode *barrier); MemBarNode *trailing_to_leading(const MemBarNode *trailing); // predicates controlling emit of ldr/ldar and associated dmb @@ -1418,23 +1416,28 @@ source %{ // leading MemBarRelease and a trailing MemBarVolatile as follows // // MemBarRelease - // { || } -- optional + // { || } -- optional // {MemBarCPUOrder} - // || \\ - // || StoreX[mo_release] - // | \ / - // | MergeMem - // | / + // || \\ + // || StoreX[mo_release] + // | \ Bot / ??? + // | MergeMem + // | / // MemBarVolatile // // where // || and \\ represent Ctl and Mem feeds via Proj nodes // | \ and / indicate further routing of the Ctl and Mem feeds // - // this is the graph we see for non-object stores. however, for a - // volatile Object store (StoreN/P) we may see other nodes below the - // leading membar because of the need for a GC pre- or post-write - // barrier. + // Note that the memory feed from the CPUOrder membar to the + // MergeMem node is an AliasIdxBot slice while the feed from the + // StoreX is for a slice determined by the type of value being + // written. + // + // the diagram above shows the graph we see for non-object stores. + // for a volatile Object store (StoreN/P) we may see other nodes + // below the leading membar because of the need for a GC pre- or + // post-write barrier. // // with most GC configurations we with see this simple variant which // includes a post-write barrier card mark. @@ -1442,7 +1445,7 @@ source %{ // MemBarRelease______________________________ // || \\ Ctl \ \\ // || StoreN/P[mo_release] CastP2X StoreB/CM - // | \ / . . . / + // | \ Bot / oop . . . / // | MergeMem // | / // || / @@ -1452,152 +1455,142 @@ source %{ // the object address to an int used to compute the card offset) and // Ctl+Mem to a StoreB node (which does the actual card mark). // - // n.b. a StoreCM node will only appear in this configuration when - // using CMS. StoreCM differs from a normal card mark write (StoreB) - // because it implies a requirement to order visibility of the card - // mark (StoreCM) relative to the object put (StoreP/N) using a - // StoreStore memory barrier (arguably this ought to be represented - // explicitly in the ideal graph but that is not how it works). This - // ordering is required for both non-volatile and volatile - // puts. Normally that means we need to translate a StoreCM using - // the sequence + // n.b. a StoreCM node is only ever used when CMS (with or without + // CondCardMark) or G1 is configured. This abstract instruction + // differs from a normal card mark write (StoreB) because it implies + // a requirement to order visibility of the card mark (StoreCM) + // after that of the object put (StoreP/N) using a StoreStore memory + // barrier. Note that this is /not/ a requirement to order the + // instructions in the generated code (that is already guaranteed by + // the order of memory dependencies). Rather it is a requirement to + // ensure visibility order which only applies on architectures like + // AArch64 which do not implement TSO. This ordering is required for + // both non-volatile and volatile puts. + // + // That implies that we need to translate a StoreCM using the + // sequence // // dmb ishst // stlrb // - // However, in the case of a volatile put if we can recognise this - // configuration and plant an stlr for the object write then we can - // omit the dmb and just plant an strb since visibility of the stlr - // is ordered before visibility of subsequent stores. StoreCM nodes - // also arise when using G1 or using CMS with conditional card - // marking. In these cases (as we shall see) we don't need to insert - // the dmb when translating StoreCM because there is already an - // intervening StoreLoad barrier between it and the StoreP/N. - // - // It is also possible to perform the card mark conditionally on it - // currently being unmarked in which case the volatile put graph - // will look slightly different + // This dmb cannot be omitted even when the associated StoreX or + // CompareAndSwapX is implemented using stlr. However, as described + // below there are circumstances where a specific GC configuration + // requires a stronger barrier in which case it can be omitted. + // + // With the Serial or Parallel GC using +CondCardMark the card mark + // is performed conditionally on it currently being unmarked in + // which case the volatile put graph looks slightly different // // MemBarRelease____________________________________________ // || \\ Ctl \ Ctl \ \\ Mem \ // || StoreN/P[mo_release] CastP2X If LoadB | - // | \ / \ | + // | \ Bot / oop \ | // | MergeMem . . . StoreB // | / / // || / // MemBarVolatile // - // It is worth noting at this stage that both the above + // It is worth noting at this stage that all the above // configurations can be uniquely identified by checking that the // memory flow includes the following subgraph: // // MemBarRelease // {MemBarCPUOrder} - // | \ . . . - // | StoreX[mo_release] . . . - // | / - // MergeMem - // | + // | \ . . . + // | StoreX[mo_release] . . . + // Bot | / oop + // MergeMem + // | // MemBarVolatile // - // This is referred to as a *normal* subgraph. It can easily be - // detected starting from any candidate MemBarRelease, - // StoreX[mo_release] or MemBarVolatile. + // This is referred to as a *normal* volatile store subgraph. It can + // easily be detected starting from any candidate MemBarRelease, + // StoreX[mo_release] or MemBarVolatile node. // - // A simple variation on this normal case occurs for an unsafe CAS - // operation. The basic graph for a non-object CAS is + // A small variation on this normal case occurs for an unsafe CAS + // operation. The basic memory flow subgraph for a non-object CAS is + // as follows // // MemBarRelease // || // MemBarCPUOrder - // || \\ . . . - // || CompareAndSwapX - // || | - // || SCMemProj - // | \ / - // | MergeMem - // | / + // | \\ . . . + // | CompareAndSwapX + // | | + // Bot | SCMemProj + // \ / Bot + // MergeMem + // / // MemBarCPUOrder // || // MemBarAcquire // // The same basic variations on this arrangement (mutatis mutandis) - // occur when a card mark is introduced. i.e. we se the same basic - // shape but the StoreP/N is replaced with CompareAndSawpP/N and the - // tail of the graph is a pair comprising a MemBarCPUOrder + - // MemBarAcquire. + // occur when a card mark is introduced. i.e. the CPUOrder MemBar + // feeds the extra CastP2X, LoadB etc nodes but the above memory + // flow subgraph is still present. + // + // This is referred to as a *normal* CAS subgraph. It can easily be + // detected starting from any candidate MemBarRelease, + // StoreX[mo_release] or MemBarAcquire node. // - // So, in the case of a CAS the normal graph has the variant form + // The code below uses two helper predicates, leading_to_trailing + // and trailing_to_leading to identify these normal graphs, one + // validating the layout starting from the top membar and searching + // down and the other validating the layout starting from the lower + // membar and searching up. // - // MemBarRelease - // MemBarCPUOrder - // | \ . . . - // | CompareAndSwapX . . . - // | | - // | SCMemProj - // | / . . . - // MergeMem - // | - // MemBarCPUOrder - // MemBarAcquire + // There are two special case GC configurations when the simple + // normal graphs above may not be generated: when using G1 (which + // always employs a conditional card mark); and when using CMS with + // conditional card marking (+CondCardMark) configured. These GCs + // are both concurrent rather than stop-the world GCs. So they + // introduce extra Ctl+Mem flow into the graph between the leading + // and trailing membar nodes, in particular enforcing stronger + // memory serialisation beween the object put and the corresponding + // conditional card mark. CMS employs a post-write GC barrier while + // G1 employs both a pre- and post-write GC barrier. // - // This graph can also easily be detected starting from any - // candidate MemBarRelease, CompareAndSwapX or MemBarAcquire. + // The post-write barrier subgraph for these configurations includes + // a MemBarVolatile node -- referred to as a card mark membar -- + // which is needed to order the card write (StoreCM) operation in + // the barrier, the preceding StoreX (or CompareAndSwapX) and Store + // operations performed by GC threads i.e. a card mark membar + // constitutes a StoreLoad barrier hence must be translated to a dmb + // ish (whether or not it sits inside a volatile store sequence). // - // the code below uses two helper predicates, leading_to_normal and - // normal_to_leading to identify these normal graphs, one validating - // the layout starting from the top membar and searching down and - // the other validating the layout starting from the lower membar - // and searching up. + // Of course, the use of the dmb ish for the card mark membar also + // implies theat the StoreCM which follows can omit the dmb ishst + // instruction. The necessary visibility ordering will already be + // guaranteed by the dmb ish. In sum, the dmb ishst instruction only + // needs to be generated for as part of the StoreCM sequence with GC + // configuration +CMS -CondCardMark. + // + // Of course all these extra barrier nodes may well be absent -- + // they are only inserted for object puts. Their potential presence + // significantly complicates the task of identifying whether a + // MemBarRelease, StoreX[mo_release], MemBarVolatile or + // MemBarAcquire forms part of a volatile put or CAS when using + // these GC configurations (see below) and also complicates the + // decision as to how to translate a MemBarVolatile and StoreCM. // - // There are two special case GC configurations when a normal graph - // may not be generated: when using G1 (which always employs a - // conditional card mark); and when using CMS with conditional card - // marking configured. These GCs are both concurrent rather than - // stop-the world GCs. So they introduce extra Ctl+Mem flow into the - // graph between the leading and trailing membar nodes, in - // particular enforcing stronger memory serialisation beween the - // object put and the corresponding conditional card mark. CMS - // employs a post-write GC barrier while G1 employs both a pre- and - // post-write GC barrier. Of course the extra nodes may be absent -- - // they are only inserted for object puts. This significantly - // complicates the task of identifying whether a MemBarRelease, - // StoreX[mo_release] or MemBarVolatile forms part of a volatile put - // when using these GC configurations (see below). It adds similar - // complexity to the task of identifying whether a MemBarRelease, - // CompareAndSwapX or MemBarAcquire forms part of a CAS. - // - // In both cases the post-write subtree includes an auxiliary - // MemBarVolatile (StoreLoad barrier) separating the object put and - // the read of the corresponding card. This poses two additional - // problems. - // - // Firstly, a card mark MemBarVolatile needs to be distinguished - // from a normal trailing MemBarVolatile. Resolving this first - // problem is straightforward: a card mark MemBarVolatile always - // projects a Mem feed to a StoreCM node and that is a unique marker + // So, thjis means that a card mark MemBarVolatile occurring in the + // post-barrier graph it needs to be distinguished from a normal + // trailing MemBarVolatile. Resolving this is straightforward: a + // card mark MemBarVolatile always projects a Mem feed to a StoreCM + // node and that is a unique marker // // MemBarVolatile (card mark) // C | \ . . . // | StoreCM . . . // . . . // - // The second problem is how the code generator is to translate the - // card mark barrier? It always needs to be translated to a "dmb - // ish" instruction whether or not it occurs as part of a volatile - // put. A StoreLoad barrier is needed after the object put to ensure - // i) visibility to GC threads of the object put and ii) visibility - // to the mutator thread of any card clearing write by a GC - // thread. Clearly a normal store (str) will not guarantee this - // ordering but neither will a releasing store (stlr). The latter - // guarantees that the object put is visible but does not guarantee - // that writes by other threads have also been observed. - // - // So, returning to the task of translating the object put and the - // leading/trailing membar nodes: what do the non-normal node graph - // look like for these 2 special cases? and how can we determine the - // status of a MemBarRelease, StoreX[mo_release] or MemBarVolatile - // in both normal and non-normal cases? + // Returning to the task of translating the object put and the + // leading/trailing membar nodes: what do the node graphs look like + // for these 2 special cases? and how can we determine the status of + // a MemBarRelease, StoreX[mo_release] or MemBarVolatile in both + // normal and non-normal cases? // // A CMS GC post-barrier wraps its card write (StoreCM) inside an If // which selects conditonal execution based on the value loaded @@ -1608,91 +1601,117 @@ source %{ // which looks like this // // MemBarRelease - // MemBarCPUOrder_(leading)__________________ - // C | M \ \\ C \ - // | \ StoreN/P[mo_release] CastP2X - // | Bot \ / - // | MergeMem - // | / - // MemBarVolatile (card mark) - // C | || M | - // | LoadB | - // | | | - // | Cmp |\ - // | / | \ - // If | \ - // | \ | \ - // IfFalse IfTrue | \ - // \ / \ | \ - // \ / StoreCM | - // \ / | | - // Region . . . | - // | \ / - // | . . . \ / Bot + // MemBarCPUOrder_(leading)____________________ + // C | | M \ \\ M | C \ + // | | \ StoreN/P[mo_release] | CastP2X + // | | Bot \ / oop \ | + // | | MergeMem \ / + // | | / | / + // MemBarVolatile (card mark) | / + // C | || M | | / + // | LoadB | Bot oop | / Bot + // | | | / / + // | Cmp |\ / / + // | / | \ / / + // If | \ / / + // | \ | \ / / + // IfFalse IfTrue | \ / / + // \ / \ | | / / + // \ / StoreCM | / / + // \ / \ / / / + // Region Phi / / + // | \ Raw | / / + // | . . . | / / // | MergeMem - // | | + // | | // MemBarVolatile (trailing) // - // The first MergeMem merges the AliasIdxBot Mem slice from the - // leading membar and the oopptr Mem slice from the Store into the - // card mark membar. The trailing MergeMem merges the AliasIdxBot - // Mem slice from the card mark membar and the AliasIdxRaw slice - // from the StoreCM into the trailing membar (n.b. the latter - // proceeds via a Phi associated with the If region). + // Notice that there are two MergeMem nodes below the leading + // membar. The first MergeMem merges the AliasIdxBot Mem slice from + // the leading membar and the oopptr Mem slice from the Store into + // the card mark membar. The trailing MergeMem merges the + // AliasIdxBot Mem slice from the leading membar, the AliasIdxRaw + // slice from the StoreCM and an oop slice from the StoreN/P node + // into the trailing membar (n.b. the raw slice proceeds via a Phi + // associated with the If region). // - // The graph for a CAS varies slightly, the obvious difference being - // that the StoreN/P node is replaced by a CompareAndSwapP/N node - // and the trailing MemBarVolatile by a MemBarCPUOrder + - // MemBarAcquire pair. The other important difference is that the - // CompareAndSwap node's SCMemProj is not merged into the card mark - // membar - it still feeds the trailing MergeMem. This also means - // that the card mark membar receives its Mem feed directly from the - // leading membar rather than via a MergeMem. + // So, in the case of CMS + CondCardMark the volatile object store + // graph still includes a normal volatile store subgraph from the + // leading membar to the trailing membar. However, it also contains + // the same shape memory flow to the card mark membar. The two flows + // can be distinguished by testing whether or not the downstream + // membar is a card mark membar. + // + // The graph for a CAS also varies with CMS + CondCardMark, in + // particular employing a control feed from the CompareAndSwapX node + // through a CmpI and If to the card mark membar and StoreCM which + // updates the associated card. This avoids executing the card mark + // if the CAS fails. However, it can be seen from the diagram below + // that the presence of the barrier does not alter the normal CAS + // memory subgraph where the leading membar feeds a CompareAndSwapX, + // an SCMemProj, a MergeMem then a final trailing MemBarCPUOrder and + // MemBarAcquire pair. // // MemBarRelease - // MemBarCPUOrder__(leading)_________________________ - // || \\ C \ - // MemBarVolatile (card mark) CompareAndSwapN/P CastP2X - // C | || M | | - // | LoadB | ______/| - // | | | / | - // | Cmp | / SCMemProj - // | / | / | - // If | / / - // | \ | / / - // IfFalse IfTrue | / / - // \ / \ |/ prec / - // \ / StoreCM / - // \ / | / - // Region . . . / - // | \ / - // | . . . \ / Bot - // | MergeMem - // | | - // MemBarCPUOrder - // MemBarAcquire (trailing) + // MemBarCPUOrder__(leading)_______________________ + // C / M | \\ C \ + // . . . | Bot CompareAndSwapN/P CastP2X + // | C / M | + // | CmpI | + // | / | + // | . . . | + // | IfTrue | + // | / | + // MemBarVolatile (card mark) | + // C | || M | | + // | LoadB | Bot ______/| + // | | | / | + // | Cmp | / SCMemProj + // | / | / | + // If | / / + // | \ | / / Bot + // IfFalse IfTrue | / / + // | / \ / / prec / + // . . . | / StoreCM / + // \ | / | raw / + // Region . . . / + // | \ / + // | . . . \ / Bot + // | MergeMem + // | / + // MemBarCPUOrder + // MemBarAcquire (trailing) // // This has a slightly different memory subgraph to the one seen - // previously but the core of it is the same as for the CAS normal - // sungraph + // previously but the core of it has a similar memory flow to the + // CAS normal subgraph: // // MemBarRelease // MemBarCPUOrder____ - // || \ . . . - // MemBarVolatile CompareAndSwapX . . . - // | \ | - // . . . SCMemProj - // | / . . . - // MergeMem - // | + // | \ . . . + // | CompareAndSwapX . . . + // | C / M | + // | CmpI | + // | / | + // | . . / + // Bot | IfTrue / + // | / / + // MemBarVolatile / + // | ... / + // StoreCM ... / + // | / + // . . . SCMemProj + // Raw \ / Bot + // MergeMem + // | // MemBarCPUOrder // MemBarAcquire // - // - // G1 is quite a lot more complicated. The nodes inserted on behalf - // of G1 may comprise: a pre-write graph which adds the old value to - // the SATB queue; the releasing store itself; and, finally, a - // post-write graph which performs a card mark. + // The G1 graph for a volatile object put is a lot more complicated. + // Nodes inserted on behalf of G1 may comprise: a pre-write graph + // which adds the old value to the SATB queue; the releasing store + // itself; and, finally, a post-write graph which performs a card + // mark. // // The pre-write graph may be omitted, but only when the put is // writing to a newly allocated (young gen) object and then only if @@ -1730,25 +1749,60 @@ source %{ // | CastP2X | StoreN/P[mo_release] | // | | | | // C | M | M | M | - // \ | | / + // \ | Raw | oop / Bot // . . . // (post write subtree elided) // . . . // C \ M / // MemBarVolatile (trailing) // + // Note that the three memory feeds into the post-write tree are an + // AliasRawIdx slice associated with the writes in the pre-write + // tree, an oop type slice from the StoreX specific to the type of + // the volatile field and the AliasBotIdx slice emanating from the + // leading membar. + // // n.b. the LoadB in this subgraph is not the card read -- it's a // read of the SATB queue active flag. // - // Once again the CAS graph is a minor variant on the above with the - // expected substitutions of CompareAndSawpX for StoreN/P and - // MemBarCPUOrder + MemBarAcquire for trailing MemBarVolatile. + // The CAS graph is once again a variant of the above with a + // CompareAndSwapX node and SCMemProj in place of the StoreX. The + // value from the CompareAndSwapX node is fed into the post-write + // graph aling with the AliasIdxRaw feed from the pre-barrier and + // the AliasIdxBot feeds from the leading membar and the ScMemProj. + // + // MemBarRelease (leading)____________ + // C | || M \ M \ M \ M \ . . . + // | LoadB \ LoadL LoadN \ + // | / \ \ + // If |\ \ + // | \ | \ \ + // IfFalse IfTrue | \ \ + // | | | \ \ + // | If | \ | + // | | \ | + // | \ | + // | . . . \ | + // | / | / \ | + // Region Phi[M] \ | + // | \ | \ | + // | \_____ | | | + // C | C \ | | | + // | CastP2X | CompareAndSwapX | + // | | res | | | + // C | M | | SCMemProj M | + // \ | Raw | | Bot / Bot + // . . . + // (post write subtree elided) + // . . . + // C \ M / + // MemBarVolatile (trailing) // // The G1 post-write subtree is also optional, this time when the // new value being written is either null or can be identified as a // newly allocated (young gen) object with no intervening control // flow. The latter cannot happen but the former may, in which case - // the card mark membar is omitted and the memory feeds form the + // the card mark membar is omitted and the memory feeds from the // leading membar and the SToreN/P are merged direct into the // trailing membar as per the normal subgraph. So, the only special // case which arises is when the post-write subgraph is generated. @@ -1770,94 +1824,106 @@ source %{ // // (pre-write subtree elided) // . . . . . . . . . . . . - // C | M | M | M | - // Region Phi[M] StoreN | - // | / \ | | - // / \_______ / \ | | - // C / C \ . . . \ | | - // If CastP2X . . . | | | - // / \ | | | - // / \ | | | - // IfFalse IfTrue | | | - // | | | | /| - // | If | | / | - // | / \ | | / | - // | / \ \ | / | - // | IfFalse IfTrue MergeMem | - // | . . . / \ / | - // | / \ / | - // | IfFalse IfTrue / | - // | . . . | / | - // | If / | - // | / \ / | - // | / \ / | - // | IfFalse IfTrue / | - // | . . . | / | - // | \ / | - // | \ / | - // | MemBarVolatile__(card mark) | - // | || C | M \ M \ | - // | LoadB If | | | - // | / \ | | | - // | . . . | | | - // | \ | | / - // | StoreCM | / - // | . . . | / - // | _________/ / - // | / _____________/ - // | . . . . . . | / / - // | | | / _________/ - // | | Phi[M] / / - // | | | / / - // | | | / / - // | Region . . . Phi[M] _____/ - // | / | / - // | | / - // | . . . . . . | / - // | / | / - // Region | | Phi[M] - // | | | / Bot - // \ MergeMem - // \ / - // MemBarVolatile + // C | M | M | M | + // Region Phi[M] StoreN | + // | Raw | oop | Bot | + // / \_______ |\ |\ |\ + // C / C \ . . . | \ | \ | \ + // If CastP2X . . . | \ | \ | \ + // / \ | \ | \ | \ + // / \ | \ | \ | \ + // IfFalse IfTrue | | | \ + // | | \ | / | + // | If \ | \ / \ | + // | / \ \ | / \ | + // | / \ \ | / \ | | + // | IfFalse IfTrue MergeMem \ | | + // | . . . / \ | \ | | + // | / \ | | | | + // | IfFalse IfTrue | | | | + // | . . . | | | | | + // | If / | | | + // | / \ / | | | + // | / \ / | | | + // | IfFalse IfTrue / | | | + // | . . . | / | | | + // | \ / | | | + // | \ / | | | + // | MemBarVolatile__(card mark ) | | | + // | || C | \ | | | + // | LoadB If | / | | + // | / \ Raw | / / / + // | . . . | / / / + // | \ | / / / + // | StoreCM / / / + // | | / / / + // | . . . / / + // | / / + // | . . . / / + // | | | / / / + // | | Phi[M] / / / + // | | | / / / + // | | | / / / + // | Region . . . Phi[M] / / + // | | | / / + // \ | | / / + // \ | . . . | / / + // \ | | / / + // Region Phi[M] / / + // | \ / / + // \ MergeMem + // \ / + // MemBarVolatile // - // As with CMS the initial MergeMem merges the AliasIdxBot Mem slice - // from the leading membar and the oopptr Mem slice from the Store - // into the card mark membar i.e. the memory flow to the card mark - // membar still looks like a normal graph. + // As with CMS + CondCardMark the first MergeMem merges the + // AliasIdxBot Mem slice from the leading membar and the oopptr Mem + // slice from the Store into the card mark membar. However, in this + // case it may also merge an AliasRawIdx mem slice from the pre + // barrier write. // - // The trailing MergeMem merges an AliasIdxBot Mem slice with other - // Mem slices (from the StoreCM and other card mark queue stores). - // However in this case the AliasIdxBot Mem slice does not come - // direct from the card mark membar. It is merged through a series - // of Phi nodes. These are needed to merge the AliasIdxBot Mem flow - // from the leading membar with the Mem feed from the card mark - // membar. Each Phi corresponds to one of the Ifs which may skip - // around the card mark membar. So when the If implementing the NULL - // value check has been elided the total number of Phis is 2 - // otherwise it is 3. + // The trailing MergeMem merges an AliasIdxBot Mem slice from the + // leading membar with an oop slice from the StoreN and an + // AliasRawIdx slice from the post barrier writes. In this case the + // AliasIdxRaw Mem slice is merged through a series of Phi nodes + // which combine feeds from the If regions in the post barrier + // subgraph. // - // The CAS graph when using G1GC also includes a pre-write subgraph - // and an optional post-write subgraph. Teh sam evarioations are - // introduced as for CMS with conditional card marking i.e. the - // StoreP/N is swapped for a CompareAndSwapP/N, the tariling - // MemBarVolatile for a MemBarCPUOrder + MemBarAcquire pair and the - // Mem feed from the CompareAndSwapP/N includes a precedence - // dependency feed to the StoreCM and a feed via an SCMemProj to the - // trailing membar. So, as before the configuration includes the - // normal CAS graph as a subgraph of the memory flow. + // So, for G1 the same characteristic subgraph arises as for CMS + + // CondCardMark. There is a normal subgraph feeding the card mark + // membar and a normal subgraph feeding the trailing membar. // - // So, the upshot is that in all cases the volatile put graph will - // include a *normal* memory subgraph betwen the leading membar and - // its child membar, either a volatile put graph (including a - // releasing StoreX) or a CAS graph (including a CompareAndSwapX). - // When that child is not a card mark membar then it marks the end - // of the volatile put or CAS subgraph. If the child is a card mark - // membar then the normal subgraph will form part of a volatile put - // subgraph if and only if the child feeds an AliasIdxBot Mem feed - // to a trailing barrier via a MergeMem. That feed is either direct - // (for CMS) or via 2 or 3 Phi nodes merging the leading barrier - // memory flow (for G1). + // The CAS graph when using G1GC also includes an optional + // post-write subgraph. It is very similar to the above graph except + // for a few details. + // + // - The control flow is gated by an additonal If which tests the + // result from the CompareAndSwapX node + // + // - The MergeMem which feeds the card mark membar only merges the + // AliasIdxBot slice from the leading membar and the AliasIdxRaw + // slice from the pre-barrier. It does not merge the SCMemProj + // AliasIdxBot slice. So, this subgraph does not look like the + // normal CAS subgraph. + // + // - The MergeMem which feeds the trailing membar merges the + // AliasIdxBot slice from the leading membar, the AliasIdxRaw slice + // from the post-barrier and the SCMemProj AliasIdxBot slice i.e. it + // has two AliasIdxBot input slices. However, this subgraph does + // still look like the normal CAS subgraph. + // + // So, the upshot is: + // + // In all cases a volatile put graph will include a *normal* + // volatile store subgraph betwen the leading membar and the + // trailing membar. It may also include a normal volatile store + // subgraph betwen the leading membar and the card mark membar. + // + // In all cases a CAS graph will contain a unique normal CAS graph + // feeding the trailing membar. + // + // In all cases where there is a card mark membar (either as part of + // a volatile object put or CAS) it will be fed by a MergeMem whose + // AliasIdxBot slice feed will be a leading membar. // // The predicates controlling generation of instructions for store // and barrier nodes employ a few simple helper functions (described @@ -1878,24 +1944,24 @@ source %{ opcode == Op_CompareAndSwapP); } - // leading_to_normal + // leading_to_trailing // //graph traversal helper which detects the normal case Mem feed from // a release membar (or, optionally, its cpuorder child) to a // dependent volatile membar i.e. it ensures that one or other of // the following Mem flow subgraph is present. // - // MemBarRelease - // MemBarCPUOrder {leading} - // | \ . . . - // | StoreN/P[mo_release] . . . - // | / - // MergeMem - // | - // MemBarVolatile {trailing or card mark} + // MemBarRelease {leading} + // {MemBarCPUOrder} {optional} + // Bot | \ . . . + // | StoreN/P[mo_release] . . . + // | / + // MergeMem + // | + // MemBarVolatile {not card mark} // - // MemBarRelease - // MemBarCPUOrder {leading} + // MemBarRelease {leading} + // {MemBarCPUOrder} {optional} // | \ . . . // | CompareAndSwapX . . . // | @@ -1906,6 +1972,23 @@ source %{ // MemBarCPUOrder // MemBarAcquire {trailing} // + // the predicate needs to be capable of distinguishing the following + // volatile put graph which may arises when a GC post barrier + // inserts a card mark membar + // + // MemBarRelease {leading} + // {MemBarCPUOrder}__ + // Bot | \ \ + // | StoreN/P \ + // | / \ | + // MergeMem \ | + // | \ | + // MemBarVolatile \ | + // {card mark} \ | + // MergeMem + // | + // {not card mark} MemBarVolatile + // // if the correct configuration is present returns the trailing // membar otherwise NULL. // @@ -1916,7 +1999,7 @@ source %{ // the returned value may be a card mark or trailing membar // - MemBarNode *leading_to_normal(MemBarNode *leading) + MemBarNode *leading_to_trailing(MemBarNode *leading) { assert((leading->Opcode() == Op_MemBarRelease || leading->Opcode() == Op_MemBarCPUOrder), @@ -1933,15 +2016,21 @@ source %{ StoreNode * st = NULL; LoadStoreNode *cas = NULL; MergeMemNode *mm = NULL; + MergeMemNode *mm2 = NULL; for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { x = mem->fast_out(i); if (x->is_MergeMem()) { if (mm != NULL) { - return NULL; + if (mm2 != NULL) { + // should not see more than 2 merge mems + return NULL; + } else { + mm2 = x->as_MergeMem(); + } + } else { + mm = x->as_MergeMem(); } - // two merge mems is one too many - mm = x->as_MergeMem(); } else if (x->is_Store() && x->as_Store()->is_release() && x->Opcode() != Op_StoreCM) { // two releasing stores/CAS nodes is one too many if (st != NULL || cas != NULL) { @@ -1961,13 +2050,13 @@ source %{ return NULL; } - // must have a merge if we also have st + // must have at least one merge if we also have st if (st && !mm) { return NULL; } - Node *y = NULL; if (cas) { + Node *y = NULL; // look for an SCMemProj for (DUIterator_Fast imax, i = cas->fast_outs(imax); i < imax; i++) { x = cas->fast_out(i); @@ -1987,10 +2076,29 @@ source %{ break; } } - if (mm == NULL) + if (mm == NULL) { return NULL; + } + MemBarNode *mbar = NULL; + // ensure the merge feeds a trailing membar cpuorder + acquire pair + for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { + x = mm->fast_out(i); + if (x->is_MemBar()) { + int opcode = x->Opcode(); + if (opcode == Op_MemBarCPUOrder) { + MemBarNode *z = x->as_MemBar(); + z = child_membar(z); + if (z != NULL && z->Opcode() == Op_MemBarAcquire) { + mbar = z; + } + } + break; + } + } + return mbar; } else { - // ensure the store feeds the existing mergemem; + Node *y = NULL; + // ensure the store feeds the first mergemem; for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { if (st->fast_out(i) == mm) { y = st; @@ -2000,55 +2108,89 @@ source %{ if (y == NULL) { return NULL; } - } - - MemBarNode *mbar = NULL; - // ensure the merge feeds to the expected type of membar - for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { - x = mm->fast_out(i); - if (x->is_MemBar()) { - int opcode = x->Opcode(); - if (opcode == Op_MemBarVolatile && st) { - mbar = x->as_MemBar(); - } else if (cas && opcode == Op_MemBarCPUOrder) { - MemBarNode *y = x->as_MemBar(); - y = child_membar(y); - if (y != NULL && y->Opcode() == Op_MemBarAcquire) { - mbar = y; + if (mm2 != NULL) { + // ensure the store feeds the second mergemem; + y = NULL; + for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { + if (st->fast_out(i) == mm2) { + y = st; } } - break; + if (y == NULL) { + return NULL; + } + } + + MemBarNode *mbar = NULL; + // ensure the first mergemem feeds a volatile membar + for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { + x = mm->fast_out(i); + if (x->is_MemBar()) { + int opcode = x->Opcode(); + if (opcode == Op_MemBarVolatile) { + mbar = x->as_MemBar(); + } + break; + } + } + if (mm2 == NULL) { + // this is our only option for a trailing membar + return mbar; + } + // ensure the second mergemem feeds a volatile membar + MemBarNode *mbar2 = NULL; + for (DUIterator_Fast imax, i = mm2->fast_outs(imax); i < imax; i++) { + x = mm2->fast_out(i); + if (x->is_MemBar()) { + int opcode = x->Opcode(); + if (opcode == Op_MemBarVolatile) { + mbar2 = x->as_MemBar(); + } + break; + } + } + // if we have two merge mems we must have two volatile membars + if (mbar == NULL || mbar2 == NULL) { + return NULL; + } + // return the trailing membar + if (is_card_mark_membar(mbar2)) { + return mbar; + } else { + if (is_card_mark_membar(mbar)) { + return mbar2; + } else { + return NULL; + } } } - - return mbar; } - // normal_to_leading + // trailing_to_leading // // graph traversal helper which detects the normal case Mem feed - // from either a card mark or a trailing membar to a preceding - // release membar (optionally its cpuorder child) i.e. it ensures - // that one or other of the following Mem flow subgraphs is present. + // from a trailing membar to a preceding release membar (optionally + // its cpuorder child) i.e. it ensures that one or other of the + // following Mem flow subgraphs is present. // - // MemBarRelease - // MemBarCPUOrder {leading} - // | \ . . . - // | StoreN/P[mo_release] . . . - // | / - // MergeMem - // | - // MemBarVolatile {card mark or trailing} + // MemBarRelease {leading} + // MemBarCPUOrder {optional} + // | Bot | \ . . . + // | | StoreN/P[mo_release] . . . + // | | / + // | MergeMem + // | | + // MemBarVolatile {not card mark} // - // MemBarRelease - // MemBarCPUOrder {leading} + // MemBarRelease {leading} + // MemBarCPUOrder {optional} // | \ . . . // | CompareAndSwapX . . . // | // . . . SCMemProj // \ | // | MergeMem - // | / + // | | // MemBarCPUOrder // MemBarAcquire {trailing} // @@ -2058,15 +2200,20 @@ source %{ // if the configuration is present returns the cpuorder member for // preference or when absent the release membar otherwise NULL. // - // n.b. the input membar is expected to be a MemBarVolatile but - // need not be a card mark membar. + // n.b. the input membar is expected to be a MemBarVolatile or + // MemBarAcquire. if it is a MemBarVolatile it must *not* be a card + // mark membar. - MemBarNode *normal_to_leading(const MemBarNode *barrier) + MemBarNode *trailing_to_leading(const MemBarNode *barrier) { // input must be a volatile membar assert((barrier->Opcode() == Op_MemBarVolatile || barrier->Opcode() == Op_MemBarAcquire), "expecting a volatile or an acquire membar"); + + assert((barrier->Opcode() != Op_MemBarVolatile) || + !is_card_mark_membar(barrier), + "not expecting a card mark membar"); Node *x; bool is_cas = barrier->Opcode() == Op_MemBarAcquire; @@ -2179,169 +2326,35 @@ source %{ return NULL; } - // card_mark_to_trailing + // card_mark_to_leading // - // graph traversal helper which detects extra, non-normal Mem feed - // from a card mark volatile membar to a trailing membar i.e. it - // ensures that one of the following three GC post-write Mem flow - // subgraphs is present. + // graph traversal helper which traverses from a card mark volatile + // membar to a leading membar i.e. it ensures that the following Mem + // flow subgraph is present. // - // 1) - // . . . - // | - // MemBarVolatile (card mark) - // | | - // | StoreCM - // | | - // | . . . - // Bot | / - // MergeMem - // | - // | - // MemBarVolatile {trailing} - // - // 2) - // MemBarRelease/CPUOrder (leading) - // | - // | - // |\ . . . - // | \ | - // | \ MemBarVolatile (card mark) - // | \ | | - // \ \ | StoreCM . . . - // \ \ | - // \ Phi - // \ / - // Phi . . . + // MemBarRelease {leading} + // {MemBarCPUOrder} {optional} + // | . . . // Bot | / - // MergeMem + // MergeMem // | - // MemBarVolatile {trailing} + // MemBarVolatile (card mark) + // | \ + // . . . StoreCM // + // if the configuration is present returns the cpuorder member for + // preference or when absent the release membar otherwise NULL. // - // 3) - // MemBarRelease/CPUOrder (leading) - // | - // |\ - // | \ - // | \ . . . - // | \ | - // |\ \ MemBarVolatile (card mark) - // | \ \ | | - // | \ \ | StoreCM . . . - // | \ \ | - // \ \ Phi - // \ \ / - // \ Phi - // \ / - // Phi . . . - // Bot | / - // MergeMem - // | - // | - // MemBarVolatile {trailing} - // - // configuration 1 is only valid if UseConcMarkSweepGC && - // UseCondCardMark - // - // configurations 2 and 3 are only valid if UseG1GC. - // - // if a valid configuration is present returns the trailing membar - // otherwise NULL. - // - // n.b. the supplied membar is expected to be a card mark - // MemBarVolatile i.e. the caller must ensure the input node has the - // correct operand and feeds Mem to a StoreCM node + // n.b. the input membar is expected to be a MemBarVolatile amd must + // be a card mark membar. - MemBarNode *card_mark_to_trailing(const MemBarNode *barrier) + MemBarNode *card_mark_to_leading(const MemBarNode *barrier) { // input must be a card mark volatile membar assert(is_card_mark_membar(barrier), "expecting a card mark membar"); - Node *feed = barrier->proj_out(TypeFunc::Memory); - Node *x; - MergeMemNode *mm = NULL; - - const int MAX_PHIS = 3; // max phis we will search through - int phicount = 0; // current search count - - bool retry_feed = true; - while (retry_feed) { - // see if we have a direct MergeMem feed - for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) { - x = feed->fast_out(i); - // the correct Phi will be merging a Bot memory slice - if (x->is_MergeMem()) { - mm = x->as_MergeMem(); - break; - } - } - if (mm) { - retry_feed = false; - } else if (UseG1GC & phicount++ < MAX_PHIS) { - // the barrier may feed indirectly via one or two Phi nodes - PhiNode *phi = NULL; - for (DUIterator_Fast imax, i = feed->fast_outs(imax); i < imax; i++) { - x = feed->fast_out(i); - // the correct Phi will be merging a Bot memory slice - if (x->is_Phi() && x->adr_type() == TypePtr::BOTTOM) { - phi = x->as_Phi(); - break; - } - } - if (!phi) { - return NULL; - } - // look for another merge below this phi - feed = phi; - } else { - // couldn't find a merge - return NULL; - } - } - - // sanity check this feed turns up as the expected slice - assert(mm->as_MergeMem()->in(Compile::AliasIdxBot) == feed, "expecting membar to feed AliasIdxBot slice to Merge"); - - MemBarNode *trailing = NULL; - // be sure we have a trailing membar the merge - for (DUIterator_Fast imax, i = mm->fast_outs(imax); i < imax; i++) { - x = mm->fast_out(i); - if (x->is_MemBar() && x->Opcode() == Op_MemBarVolatile) { - trailing = x->as_MemBar(); - break; - } - } - - return trailing; - } - - // trailing_to_card_mark - // - // graph traversal helper which detects extra, non-normal Mem feed - // from a trailing volatile membar to a preceding card mark volatile - // membar i.e. it identifies whether one of the three possible extra - // GC post-write Mem flow subgraphs is present - // - // this predicate checks for the same flow as the previous predicate - // but starting from the bottom rather than the top. - // - // if the configuration is present returns the card mark membar - // otherwise NULL - // - // n.b. the supplied membar is expected to be a trailing - // MemBarVolatile i.e. the caller must ensure the input node has the - // correct opcode - - MemBarNode *trailing_to_card_mark(const MemBarNode *trailing) - { - assert(trailing->Opcode() == Op_MemBarVolatile, - "expecting a volatile membar"); - assert(!is_card_mark_membar(trailing), - "not expecting a card mark membar"); - // the Mem feed to the membar should be a merge - Node *x = trailing->in(TypeFunc::Memory); + Node *x = barrier->in(TypeFunc::Memory); if (!x->is_MergeMem()) { return NULL; } @@ -2349,118 +2362,20 @@ source %{ MergeMemNode *mm = x->as_MergeMem(); x = mm->in(Compile::AliasIdxBot); - // with G1 we may possibly see a Phi or two before we see a Memory - // Proj from the card mark membar - const int MAX_PHIS = 3; // max phis we will search through - int phicount = 0; // current search count - - bool retry_feed = !x->is_Proj(); - - while (retry_feed) { - if (UseG1GC && x->is_Phi() && phicount++ < MAX_PHIS) { - PhiNode *phi = x->as_Phi(); - ProjNode *proj = NULL; - PhiNode *nextphi = NULL; - bool found_leading = false; - for (uint i = 1; i < phi->req(); i++) { - x = phi->in(i); - if (x->is_Phi()) { - nextphi = x->as_Phi(); - } else if (x->is_Proj()) { - int opcode = x->in(0)->Opcode(); - if (opcode == Op_MemBarVolatile) { - proj = x->as_Proj(); - } else if (opcode == Op_MemBarRelease || - opcode == Op_MemBarCPUOrder) { - // probably a leading membar - found_leading = true; - } - } - } - // if we found a correct looking proj then retry from there - // otherwise we must see a leading and a phi or this the - // wrong config - if (proj != NULL) { - x = proj; - retry_feed = false; - } else if (found_leading && nextphi != NULL) { - // retry from this phi to check phi2 - x = nextphi; - } else { - // not what we were looking for - return NULL; - } - } else { - return NULL; - } - } - // the proj has to come from the card mark membar - x = x->in(0); if (!x->is_MemBar()) { return NULL; } - MemBarNode *card_mark_membar = x->as_MemBar(); + MemBarNode *leading = x->as_MemBar(); - if (!is_card_mark_membar(card_mark_membar)) { - return NULL; - } - - return card_mark_membar; - } - - // trailing_to_leading - // - // graph traversal helper which checks the Mem flow up the graph - // from a (non-card mark) trailing membar attempting to locate and - // return an associated leading membar. it first looks for a - // subgraph in the normal configuration (relying on helper - // normal_to_leading). failing that it then looks for one of the - // possible post-write card mark subgraphs linking the trailing node - // to a the card mark membar (relying on helper - // trailing_to_card_mark), and then checks that the card mark membar - // is fed by a leading membar (once again relying on auxiliary - // predicate normal_to_leading). - // - // if the configuration is valid returns the cpuorder member for - // preference or when absent the release membar otherwise NULL. - // - // n.b. the input membar is expected to be either a volatile or - // acquire membar but in the former case must *not* be a card mark - // membar. - - MemBarNode *trailing_to_leading(const MemBarNode *trailing) - { - assert((trailing->Opcode() == Op_MemBarAcquire || - trailing->Opcode() == Op_MemBarVolatile), - "expecting an acquire or volatile membar"); - assert((trailing->Opcode() != Op_MemBarVolatile || - !is_card_mark_membar(trailing)), - "not expecting a card mark membar"); - - MemBarNode *leading = normal_to_leading(trailing); - - if (leading) { + if (leading_membar(leading)) { return leading; } - // nothing more to do if this is an acquire - if (trailing->Opcode() == Op_MemBarAcquire) { - return NULL; - } - - MemBarNode *card_mark_membar = trailing_to_card_mark(trailing); - - if (!card_mark_membar) { - return NULL; - } - - return normal_to_leading(card_mark_membar); + return NULL; } - // predicates controlling emit of ldr/ldar and associated dmb - bool unnecessary_acquire(const Node *barrier) { assert(barrier->is_MemBar(), "expecting a membar"); @@ -2675,19 +2590,8 @@ bool unnecessary_release(const Node *n) } // must start with a normal feed - MemBarNode *child_barrier = leading_to_normal(barrier); + MemBarNode *trailing = leading_to_trailing(barrier); - if (!child_barrier) { - return false; - } - - if (!is_card_mark_membar(child_barrier)) { - // this is the trailing membar and we are done - return true; - } - - // must be sure this card mark feeds a trailing membar - MemBarNode *trailing = card_mark_to_trailing(child_barrier); return (trailing != NULL); } @@ -2709,7 +2613,7 @@ bool unnecessary_volatile(const Node *n) } // ok, if it's not a card mark then we still need to check if it is - // a trailing membar of a volatile put hgraph. + // a trailing membar of a volatile put graph. return (trailing_to_leading(mbvol) != NULL); } @@ -2759,20 +2663,9 @@ bool needs_releasing_store(const Node *n) } // does this lead a normal subgraph? - MemBarNode *mbvol = leading_to_normal(barrier); + MemBarNode *trailing = leading_to_trailing(barrier); - if (!mbvol) { - return false; - } - - // all done unless this is a card mark - if (!is_card_mark_membar(mbvol)) { - return true; - } - - // we found a card mark -- just make sure we have a trailing barrier - - return (card_mark_to_trailing(mbvol) != NULL); + return (trailing != NULL); } // predicate controlling translation of CAS @@ -2814,7 +2707,7 @@ bool needs_acquiring_load_exclusive(const Node *n) "CAS not fed by cpuorder+release membar pair!"); // does this lead a normal subgraph? - MemBarNode *mbar = leading_to_normal(barrier); + MemBarNode *mbar = leading_to_trailing(barrier); assert(mbar != NULL, "CAS not embedded in normal graph!"); @@ -2835,48 +2728,27 @@ bool unnecessary_storestore(const Node *storecm) // we only ever need to generate a dmb ishst between an object put // and the associated card mark when we are using CMS without - // conditional card marking + // conditional card marking. Any other occurence will happen when + // performing a card mark using CMS with conditional card marking or + // G1. In those cases the preceding MamBarVolatile will be + // translated to a dmb ish which guarantes visibility of the + // preceding StoreN/P before this StoreCM if (!UseConcMarkSweepGC || UseCondCardMark) { return true; } - // if we are implementing volatile puts using barriers then the - // object put as an str so we must insert the dmb ishst + // if we are implementing volatile puts using barriers then we must + // insert the dmb ishst if (UseBarriersForVolatile) { return false; } - // we can omit the dmb ishst if this StoreCM is part of a volatile - // put because in thta case the put will be implemented by stlr - // - // we need to check for a normal subgraph feeding this StoreCM. - // that means the StoreCM must be fed Memory from a leading membar, - // either a MemBarRelease or its dependent MemBarCPUOrder, and the - // leading membar must be part of a normal subgraph + // we must be using CMS with conditional card marking so we ahve to + // generate the StoreStore - Node *x = storecm->in(StoreNode::Memory); - - if (!x->is_Proj()) { - return false; - } - - x = x->in(0); - - if (!x->is_MemBar()) { - return false; - } - - MemBarNode *leading = x->as_MemBar(); - - // reject invalid candidates - if (!leading_membar(leading)) { - return false; - } - - // we can omit the StoreStore if it is the head of a normal subgraph - return (leading_to_normal(leading) != NULL); + return false; } diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index f3389bd969b..a47897db8c1 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -3149,6 +3149,19 @@ Node* GraphKit::insert_mem_bar_volatile(int opcode, int alias_idx, Node* precede return membar; } +void GraphKit::insert_store_load_for_barrier() { + Node* mem = reset_memory(); + MemBarNode* mb = MemBarNode::make(C, Op_MemBarVolatile, Compile::AliasIdxBot); + mb->init_req(TypeFunc::Control, control()); + mb->init_req(TypeFunc::Memory, mem); + Node* membar = _gvn.transform(mb); + set_control(_gvn.transform(new ProjNode(membar, TypeFunc::Control))); + Node* newmem = _gvn.transform(new ProjNode(membar, TypeFunc::Memory)); + set_all_memory(mem); + set_memory(newmem, Compile::AliasIdxRaw); +} + + //------------------------------shared_lock------------------------------------ // Emit locking code. FastLockNode* GraphKit::shared_lock(Node* obj) { @@ -3840,7 +3853,7 @@ void GraphKit::write_barrier_post(Node* oop_store, BasicType bt = T_BYTE; if (UseConcMarkSweepGC && UseCondCardMark) { - insert_mem_bar(Op_MemBarVolatile); // StoreLoad barrier + insert_store_load_for_barrier(); __ sync_kit(this); } @@ -4280,8 +4293,7 @@ void GraphKit::g1_write_barrier_post(Node* oop_store, __ if_then(card_val, BoolTest::ne, young_card); { sync_kit(ideal); - // Use Op_MemBarVolatile to achieve the effect of a StoreLoad barrier. - insert_mem_bar(Op_MemBarVolatile, oop_store); + insert_store_load_for_barrier(); __ sync_kit(this); Node* card_val_reload = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index 7bb1f6946db..218e937818b 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -834,6 +834,7 @@ class GraphKit : public Phase { int next_monitor(); Node* insert_mem_bar(int opcode, Node* precedent = NULL); Node* insert_mem_bar_volatile(int opcode, int alias_idx, Node* precedent = NULL); + void insert_store_load_for_barrier(); // Optional 'precedent' is appended as an extra edge, to force ordering. FastLockNode* shared_lock(Node* obj); void shared_unlock(Node* box, Node* obj); From db36e29ab02080fa72d210f6e69cee857870fc7a Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 16 Feb 2016 12:54:20 +0100 Subject: [PATCH 020/183] 8149916: Test case for 8149797 Reviewed-by: kvn --- .../c2/TestDominatingDeadCheckCast.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 hotspot/test/compiler/c2/TestDominatingDeadCheckCast.java diff --git a/hotspot/test/compiler/c2/TestDominatingDeadCheckCast.java b/hotspot/test/compiler/c2/TestDominatingDeadCheckCast.java new file mode 100644 index 00000000000..3c8f153a17c --- /dev/null +++ b/hotspot/test/compiler/c2/TestDominatingDeadCheckCast.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8149797 + * @summary node replaced by dominating dead cast during parsing + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:TypeProfileLevel=200 -XX:CompileCommand=dontinline,TestDominatingDeadCheckCast::not_inlined TestDominatingDeadCheckCast + * + */ + +public class TestDominatingDeadCheckCast { + + static class A { + int f; + } + + static class B extends A { + } + + static A not_inlined() { + return new A(); + } + + static void inlined(A param) { + param.f = 42; + } + + static A field; + + static void test(boolean flag1, boolean flag2, boolean flag3, boolean flag4, boolean flag5) { + // Go through memory rather than through a local to defeat C2's replace_in_map + field = not_inlined(); + // Speculation adds a CheckCast on entry of this inlined + // method for the parameter + inlined(field); + // Walk up the dominators is depth limited, make the CheckCast + // above unreachable from the last inlined call + if (flag1) { + if (flag2) { + if (flag3) { + // Speculation adds a CheckCast on entry of this + // inlined method for the parameter. This + // CheckCast is replaced by the CheckCast of the + // first inlined method call but the replaced + // CheckCast is still around during parsing. + inlined(field); + // Same as above, some useless control + if (flag4) { + if (flag5) { + // Speculation adds a CheckCast on entry + // of this inlined method for the + // parameter. This CheckCast is replaced + // by the dead CheckCast of the previous + // inlined() call. + inlined(field); + } + } + } + } + } + } + + static public void main(String[] args) { + field = new A(); + for (int i = 0; i < 20000; i++) { + test(true, true, true, true, true); + } + } +} From 58fe974cb716c70be3a7f304d582546141b6e0f1 Mon Sep 17 00:00:00 2001 From: Peter Brunet Date: Tue, 16 Feb 2016 19:38:26 -0600 Subject: [PATCH 021/183] 8149161: CSM call Class.forName in com.sun.java.accessibility.util.Translator Add call to checkPackageAccess Reviewed-by: serb, prr --- .../com/sun/java/accessibility/util/Translator.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java index 177fbb4403c..224b5375283 100644 --- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java @@ -32,6 +32,7 @@ import java.util.*; import java.awt.*; import java.awt.event.*; import java.awt.image.*; +import java.security.AccessControlException; // Do not import Swing classes. This module is intended to work // with both Swing and AWT. // import javax.swing.*; @@ -77,7 +78,7 @@ public class Translator extends AccessibleContext return null; } try { - t = Class.forName("com.sun.java.accessibility.util.internal" + t = Class.forName("com.sun.java.accessibility.util.internal." + c.getSimpleName() + "Translator"); return t; @@ -105,6 +106,10 @@ public class Translator extends AccessibleContext if (o instanceof Accessible) { a = (Accessible)o; } else { + // About to "newInstance" an object of a class of a restricted package + // so ensure the caller is allowed access to that package. + String pkg = "com.sun.java.accessibility.util.internal"; + System.getSecurityManager().checkPackageAccess(pkg); Class translatorClass = getTranslatorClass(o.getClass()); if (translatorClass != null) { try { From 8372c1c09a468d5c09ff115873c15721a22d2197 Mon Sep 17 00:00:00 2001 From: Avik Niyogi Date: Wed, 17 Feb 2016 11:44:07 +0530 Subject: [PATCH 022/183] 8146321: [macosx] JInternalFrame frame icon in wrong position on Mac L&F if icon is not ImageIcon Reviewed-by: serb, alexsch, rchamyal --- .../apple/laf/AquaInternalFrameBorder.java | 49 +++- .../8146321/JInternalFrameIconTest.java | 275 ++++++++++++++++++ 2 files changed, 309 insertions(+), 15 deletions(-) create mode 100644 jdk/test/javax/swing/JInternalFrame/8146321/JInternalFrameIconTest.java diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java index ef5ca43cf23..4a72d0fd371 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java @@ -40,6 +40,7 @@ import apple.laf.JRSUIState.TitleBarHeightState; import com.apple.laf.AquaUtils.RecyclableSingleton; import com.apple.laf.AquaInternalFrameBorderMetrics; +import java.awt.geom.AffineTransform; public class AquaInternalFrameBorder implements Border, UIResource { private static final int kCloseButton = 0; @@ -309,18 +310,40 @@ public class AquaInternalFrameBorder implements Border, UIResource { return isInsideYButtonArea(i, y) && x >= startX && x <= endX; } - protected void paintTitleIcon(final Graphics g, final JInternalFrame frame, final int x, final int y) { - Icon icon = frame.getFrameIcon(); - if (icon == null) icon = UIManager.getIcon("InternalFrame.icon"); - if (icon == null) return; + protected void paintTitleIcon(final Graphics g, final JInternalFrame frame, + final int x, final int y) { - // Resize to 16x16 if necessary. - if (icon instanceof ImageIcon && (icon.getIconWidth() > sMaxIconWidth || icon.getIconHeight() > sMaxIconHeight)) { - final Image img = ((ImageIcon)icon).getImage(); - ((ImageIcon)icon).setImage(img.getScaledInstance(sMaxIconWidth, sMaxIconHeight, Image.SCALE_SMOOTH)); + Icon icon = frame.getFrameIcon(); + if (icon == null) { + icon = UIManager.getIcon("InternalFrame.icon"); } - icon.paintIcon(frame, g, x, y); + if (icon == null) { + return; + } + + if (icon.getIconWidth() > sMaxIconWidth + || icon.getIconHeight() > sMaxIconHeight) { + final Graphics2D g2 = (Graphics2D) g; + final AffineTransform savedAT = g2.getTransform(); + double xScaleFactor = (double) sMaxIconWidth / icon.getIconWidth(); + double yScaleFactor = (double) sMaxIconHeight / icon.getIconHeight(); + + //Coordinates are after a translation hence relative origin shifts + g2.translate(x, y); + + //scaling factor is needed to scale while maintaining aspect ratio + double scaleMaintainAspectRatio = Math.min(xScaleFactor, yScaleFactor); + + //minimum value is taken to set to a maximum Icon Dimension + g2.scale(scaleMaintainAspectRatio, scaleMaintainAspectRatio); + + icon.paintIcon(frame, g2, 0, 0); + g2.setTransform(savedAT); + + } else { + icon.paintIcon(frame, g, x, y); + } } protected int getIconWidth(final JInternalFrame frame) { @@ -330,9 +353,7 @@ public class AquaInternalFrameBorder implements Border, UIResource { if (icon == null) { icon = UIManager.getIcon("InternalFrame.icon"); } - - if (icon != null && icon instanceof ImageIcon) { - // Resize to 16x16 if necessary. + if (icon != null) { width = Math.min(icon.getIconWidth(), sMaxIconWidth); } @@ -346,9 +367,7 @@ public class AquaInternalFrameBorder implements Border, UIResource { if (icon == null) { icon = UIManager.getIcon("InternalFrame.icon"); } - - if (icon != null && icon instanceof ImageIcon) { - // Resize to 16x16 if necessary. + if (icon != null) { height = Math.min(icon.getIconHeight(), sMaxIconHeight); } diff --git a/jdk/test/javax/swing/JInternalFrame/8146321/JInternalFrameIconTest.java b/jdk/test/javax/swing/JInternalFrame/8146321/JInternalFrameIconTest.java new file mode 100644 index 00000000000..4ff95c5bc30 --- /dev/null +++ b/jdk/test/javax/swing/JInternalFrame/8146321/JInternalFrameIconTest.java @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8146321 + * @summary verifies JInternalFrame Icon and ImageIcon + * @library ../../regtesthelpers + * @build Util + * @run main JInternalFrameIconTest + */ +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +public class JInternalFrameIconTest { + + private static JFrame frame; + private static JDesktopPane desktopPane; + private static JInternalFrame internalFrame; + private static ImageIcon titleImageIcon; + private static Icon titleIcon; + private static BufferedImage imageIconImage; + private static BufferedImage iconImage; + + private static Robot robot; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.delay(2000); + UIManager.LookAndFeelInfo[] lookAndFeelArray + = UIManager.getInstalledLookAndFeels(); + for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) { + executeCase(lookAndFeelItem.getClassName()); + } + + } + + private static void executeCase(String lookAndFeelString) throws Exception { + if (tryLookAndFeel(lookAndFeelString)) { + createImageIconUI(lookAndFeelString); + robot.delay(1000); + getImageIconBufferedImage(); + robot.waitForIdle(); + cleanUp(); + robot.waitForIdle(); + + createIconUI(lookAndFeelString); + robot.delay(1000); + getIconBufferedImage(); + robot.waitForIdle(); + cleanUp(); + robot.waitForIdle(); + testIfSame(); + robot.waitForIdle(); + } + + } + + private static void createImageIconUI(final String lookAndFeelString) + throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + desktopPane = new JDesktopPane(); + internalFrame = new JInternalFrame(); + frame = new JFrame(); + internalFrame.setTitle(lookAndFeelString); + titleImageIcon = new ImageIcon() { + @Override + public int getIconWidth() { + return 16; + } + + @Override + public int getIconHeight() { + return 16; + } + + @Override + public void paintIcon( + Component c, Graphics g, int x, int y) { + g.setColor(java.awt.Color.black); + g.fillRect(x, y, 16, 16); + } + }; + internalFrame.setFrameIcon(titleImageIcon); + internalFrame.setSize(500, 200); + internalFrame.setVisible(true); + desktopPane.add(internalFrame); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.getContentPane().setLayout(new BorderLayout()); + frame.getContentPane().add(desktopPane, "Center"); + frame.setSize(500, 500); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.toFront(); + } + }); + } + + private static void createIconUI(final String lookAndFeelString) + throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + desktopPane = new JDesktopPane(); + internalFrame = new JInternalFrame(); + frame = new JFrame(); + internalFrame.setTitle(lookAndFeelString); + titleIcon = new Icon() { + @Override + public int getIconWidth() { + return 16; + } + + @Override + public int getIconHeight() { + return 16; + } + + @Override + public void paintIcon( + Component c, Graphics g, int x, int y) { + g.setColor(java.awt.Color.black); + g.fillRect(x, y, 16, 16); + } + }; + internalFrame.setFrameIcon(titleIcon); + internalFrame.setSize(500, 200); + internalFrame.setVisible(true); + desktopPane.add(internalFrame); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.getContentPane().setLayout(new BorderLayout()); + frame.getContentPane().add(desktopPane, "Center"); + frame.setSize(500, 500); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.toFront(); + } + }); + } + + private static void getImageIconBufferedImage() throws Exception { + Point point = internalFrame.getLocationOnScreen(); + Rectangle rect = internalFrame.getBounds(); + Rectangle captureRect = new Rectangle( + point.x + internalFrame.getInsets().left, + point.y, + rect.width, + internalFrame.getInsets().top); + imageIconImage + = robot.createScreenCapture(captureRect); + } + + private static void getIconBufferedImage() throws Exception { + Point point = internalFrame.getLocationOnScreen(); + Rectangle rect = internalFrame.getBounds(); + Rectangle captureRect = new Rectangle( + point.x + internalFrame.getInsets().left, + point.y, + rect.width, + internalFrame.getInsets().top); + iconImage + = robot.createScreenCapture(captureRect); + } + + private static void testIfSame() throws Exception { + if (!bufferedImagesEqual(imageIconImage, iconImage)) { + System.err.println("ERROR: icon and imageIcon not same."); + } else { + System.out.println("SUCCESS: icon and imageIcon same."); + } + } + + private static boolean bufferedImagesEqual( + BufferedImage bufferedImage1, BufferedImage bufferedImage2) { + boolean flag = true; + + if (bufferedImage1.getWidth() == bufferedImage2.getWidth() + && bufferedImage1.getHeight() == bufferedImage2.getHeight()) { + final int colorTolerance = 25; + final int mismatchTolerance = (int) (0.1 + * bufferedImage1.getWidth() * bufferedImage1.getHeight()); + int mismatchCounter = 0; + for (int x = 0; x < bufferedImage1.getWidth(); x++) { + for (int y = 0; y < bufferedImage1.getHeight(); y++) { + + int color1 = bufferedImage1.getRGB(x, y); + int red1 = (color1 >> 16) & 0x000000FF; + int green1 = (color1 >> 8) & 0x000000FF; + int blue1 = (color1) & 0x000000FF; + + int color2 = bufferedImage2.getRGB(x, y); + int red2 = (color2 >> 16) & 0x000000FF; + int green2 = (color2 >> 8) & 0x000000FF; + int blue2 = (color2) & 0x000000FF; + if (red1 != red2 || green1 != green2 || blue1 != blue2) { + ++mismatchCounter; + if ((Math.abs(red1 - red2) > colorTolerance) + || (Math.abs(green1 - green2) > colorTolerance) + || (Math.abs(blue1 - blue2) > colorTolerance)) { + + flag = false; + } + } + } + } + if (mismatchCounter > mismatchTolerance) { + flag = false; + } + } else { + System.err.println("ERROR: size is different"); + flag = false; + } + return flag; + } + + private static void cleanUp() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame.dispose(); + } + }); + } + + private static boolean tryLookAndFeel(String lookAndFeelString) + throws Exception { + try { + UIManager.setLookAndFeel( + lookAndFeelString); + + } catch (UnsupportedLookAndFeelException + | ClassNotFoundException + | InstantiationException + | IllegalAccessException e) { + return false; + } + return true; + } +} From 98eca9ebe8872f0e2227893a8aa4f19d8f74974d Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 17 Feb 2016 10:59:04 +0100 Subject: [PATCH 023/183] 8148786: xml.tranform fails on x86-64 CCP computes wrong type for CountedLoop iv Phi Reviewed-by: kvn --- hotspot/src/share/vm/opto/loopnode.hpp | 17 +++++++-- hotspot/src/share/vm/opto/phaseX.cpp | 52 ++++++++++++++++++++------ hotspot/src/share/vm/opto/phaseX.hpp | 2 +- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index b0f3ad5d2a5..c853a2a6145 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -285,20 +285,29 @@ public: Node *incr() const { Node *tmp = cmp_node(); return (tmp && tmp->req()==3) ? tmp->in(1) : NULL; } Node *limit() const { Node *tmp = cmp_node(); return (tmp && tmp->req()==3) ? tmp->in(2) : NULL; } Node *stride() const { Node *tmp = incr (); return (tmp && tmp->req()==3) ? tmp->in(2) : NULL; } - Node *phi() const { Node *tmp = incr (); return (tmp && tmp->req()==3) ? tmp->in(1) : NULL; } Node *init_trip() const { Node *tmp = phi (); return (tmp && tmp->req()==3) ? tmp->in(1) : NULL; } int stride_con() const; bool stride_is_con() const { Node *tmp = stride (); return (tmp != NULL && tmp->is_Con()); } BoolTest::mask test_trip() const { return in(TestValue)->as_Bool()->_test._test; } + PhiNode *phi() const { + Node *tmp = incr(); + if (tmp && tmp->req() == 3) { + Node* phi = tmp->in(1); + if (phi->is_Phi()) { + return phi->as_Phi(); + } + } + return NULL; + } CountedLoopNode *loopnode() const { // The CountedLoopNode that goes with this CountedLoopEndNode may // have been optimized out by the IGVN so be cautious with the // pattern matching on the graph - if (phi() == NULL) { + PhiNode* iv_phi = phi(); + if (iv_phi == NULL) { return NULL; } - assert(phi()->is_Phi(), "should be PhiNode"); - Node *ln = phi()->in(0); + Node *ln = iv_phi->in(0); if (ln->is_CountedLoop() && ln->as_CountedLoop()->loopexit() == this) { return (CountedLoopNode*)ln; } diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp index 1f6de0d1700..f925cd5ef27 100644 --- a/hotspot/src/share/vm/opto/phaseX.cpp +++ b/hotspot/src/share/vm/opto/phaseX.cpp @@ -1471,6 +1471,27 @@ void PhaseIterGVN::add_users_to_worklist0( Node *n ) { } } +// Return counted loop Phi if as a counted loop exit condition, cmp +// compares the the induction variable with n +static PhiNode* countedloop_phi_from_cmp(CmpINode* cmp, Node* n) { + for (DUIterator_Fast imax, i = cmp->fast_outs(imax); i < imax; i++) { + Node* bol = cmp->fast_out(i); + for (DUIterator_Fast i2max, i2 = bol->fast_outs(i2max); i2 < i2max; i2++) { + Node* iff = bol->fast_out(i2); + if (iff->is_CountedLoopEnd()) { + CountedLoopEndNode* cle = iff->as_CountedLoopEnd(); + if (cle->limit() == n) { + PhiNode* phi = cle->phi(); + if (phi != NULL) { + return phi; + } + } + } + } + } + return NULL; +} + void PhaseIterGVN::add_users_to_worklist( Node *n ) { add_users_to_worklist0(n); @@ -1500,18 +1521,7 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) { Node* bol = use->raw_out(0); if (bol->outcnt() > 0) { Node* iff = bol->raw_out(0); - if (use_op == Op_CmpI && - iff->is_CountedLoopEnd()) { - CountedLoopEndNode* cle = iff->as_CountedLoopEnd(); - if (cle->limit() == n && cle->phi() != NULL) { - // If an opaque node feeds into the limit condition of a - // CountedLoop, we need to process the Phi node for the - // induction variable when the opaque node is removed: - // the range of values taken by the Phi is now known and - // so its type is also known. - _worklist.push(cle->phi()); - } - } else if (iff->outcnt() == 2) { + if (iff->outcnt() == 2) { // Look for the 'is_x2logic' pattern: "x ? : 0 : 1" and put the // phi merging either 0 or 1 onto the worklist Node* ifproj0 = iff->raw_out(0); @@ -1526,6 +1536,15 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) { } } if (use_op == Op_CmpI) { + Node* phi = countedloop_phi_from_cmp((CmpINode*)use, n); + if (phi != NULL) { + // If an opaque node feeds into the limit condition of a + // CountedLoop, we need to process the Phi node for the + // induction variable when the opaque node is removed: + // the range of values taken by the Phi is now known and + // so its type is also known. + _worklist.push(phi); + } Node* in1 = use->in(1); for (uint i = 0; i < in1->outcnt(); i++) { if (in1->raw_out(i)->Opcode() == Op_CastII) { @@ -1714,6 +1733,15 @@ void PhaseCCP::analyze() { } } } + // If n is used in a counted loop exit condition then the type + // of the counted loop's Phi depends on the type of n. See + // PhiNode::Value(). + if (m_op == Op_CmpI) { + PhiNode* phi = countedloop_phi_from_cmp((CmpINode*)m, n); + if (phi != NULL) { + worklist.push(phi); + } + } } } } diff --git a/hotspot/src/share/vm/opto/phaseX.hpp b/hotspot/src/share/vm/opto/phaseX.hpp index 837118d177a..6ef389e8649 100644 --- a/hotspot/src/share/vm/opto/phaseX.hpp +++ b/hotspot/src/share/vm/opto/phaseX.hpp @@ -431,7 +431,7 @@ public: // Phase for iteratively performing local, pessimistic GVN-style optimizations. // and ideal transformations on the graph. class PhaseIterGVN : public PhaseGVN { - private: +private: bool _delay_transform; // When true simply register the node when calling transform // instead of actually optimizing it From 8dd35ed3dd37a2f0a931290d0a9bf4ab8486ffb1 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Wed, 17 Feb 2016 14:06:45 +0000 Subject: [PATCH 024/183] 8150045: arraycopy causes segfaults in SATB during garbage collection Reviewed-by: roland --- .../cpu/aarch64/vm/stubGenerator_aarch64.cpp | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp index 554495da44e..64833c5ccc4 100644 --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp @@ -666,7 +666,7 @@ class StubGenerator: public StubCodeGenerator { // count - element count // tmp - scratch register // - // Destroy no registers! + // Destroy no registers except rscratch1 and rscratch2 // void gen_write_ref_array_pre_barrier(Register addr, Register count, bool dest_uninitialized) { BarrierSet* bs = Universe::heap()->barrier_set(); @@ -674,12 +674,13 @@ class StubGenerator: public StubCodeGenerator { case BarrierSet::G1SATBCTLogging: // With G1, don't generate the call if we statically know that the target in uninitialized if (!dest_uninitialized) { - __ push(RegSet::range(r0, r29), sp); // integer registers except lr & sp + __ push_call_clobbered_registers(); if (count == c_rarg0) { if (addr == c_rarg1) { // exactly backwards!! - __ stp(c_rarg0, c_rarg1, __ pre(sp, -2 * wordSize)); - __ ldp(c_rarg1, c_rarg0, __ post(sp, -2 * wordSize)); + __ mov(rscratch1, c_rarg0); + __ mov(c_rarg0, c_rarg1); + __ mov(c_rarg1, rscratch1); } else { __ mov(c_rarg1, count); __ mov(c_rarg0, addr); @@ -689,7 +690,7 @@ class StubGenerator: public StubCodeGenerator { __ mov(c_rarg1, count); } __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre), 2); - __ pop(RegSet::range(r0, r29), sp); // integer registers except lr & sp } + __ pop_call_clobbered_registers(); break; case BarrierSet::CardTableForRS: case BarrierSet::CardTableExtension: @@ -719,7 +720,7 @@ class StubGenerator: public StubCodeGenerator { case BarrierSet::G1SATBCTLogging: { - __ push(RegSet::range(r0, r29), sp); // integer registers except lr & sp + __ push_call_clobbered_registers(); // must compute element count unless barrier set interface is changed (other platforms supply count) assert_different_registers(start, end, scratch); __ lea(scratch, Address(end, BytesPerHeapOop)); @@ -728,7 +729,7 @@ class StubGenerator: public StubCodeGenerator { __ mov(c_rarg0, start); __ mov(c_rarg1, scratch); __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), 2); - __ pop(RegSet::range(r0, r29), sp); // integer registers except lr & sp } + __ pop_call_clobbered_registers(); } break; case BarrierSet::CardTableForRS: @@ -1394,10 +1395,10 @@ class StubGenerator: public StubCodeGenerator { // no-overlap entry point used by generate_conjoint_long_oop_copy(). // address generate_disjoint_oop_copy(bool aligned, address *entry, - const char *name, bool dest_uninitialized = false) { + const char *name, bool dest_uninitialized) { const bool is_oop = true; const size_t size = UseCompressedOops ? sizeof (jint) : sizeof (jlong); - return generate_disjoint_copy(size, aligned, is_oop, entry, name); + return generate_disjoint_copy(size, aligned, is_oop, entry, name, dest_uninitialized); } // Arguments: @@ -1412,10 +1413,11 @@ class StubGenerator: public StubCodeGenerator { // address generate_conjoint_oop_copy(bool aligned, address nooverlap_target, address *entry, - const char *name, bool dest_uninitialized = false) { + const char *name, bool dest_uninitialized) { const bool is_oop = true; const size_t size = UseCompressedOops ? sizeof (jint) : sizeof (jlong); - return generate_conjoint_copy(size, aligned, is_oop, nooverlap_target, entry, name); + return generate_conjoint_copy(size, aligned, is_oop, nooverlap_target, entry, + name, dest_uninitialized); } @@ -1522,6 +1524,8 @@ class StubGenerator: public StubCodeGenerator { } #endif //ASSERT + gen_write_ref_array_pre_barrier(to, count, dest_uninitialized); + // save the original count __ mov(count_save, count); @@ -1988,9 +1992,11 @@ class StubGenerator: public StubCodeGenerator { bool aligned = !UseCompressedOops; StubRoutines::_arrayof_oop_disjoint_arraycopy - = generate_disjoint_oop_copy(aligned, &entry, "arrayof_oop_disjoint_arraycopy"); + = generate_disjoint_oop_copy(aligned, &entry, "arrayof_oop_disjoint_arraycopy", + /*dest_uninitialized*/false); StubRoutines::_arrayof_oop_arraycopy - = generate_conjoint_oop_copy(aligned, entry, &entry_oop_arraycopy, "arrayof_oop_arraycopy"); + = generate_conjoint_oop_copy(aligned, entry, &entry_oop_arraycopy, "arrayof_oop_arraycopy", + /*dest_uninitialized*/false); // Aligned versions without pre-barriers StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit = generate_disjoint_oop_copy(aligned, &entry, "arrayof_oop_disjoint_arraycopy_uninit", From 1e654fe813b220aa97d80ae2b6320a2002dd3aa2 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 19 Feb 2016 11:16:38 +0300 Subject: [PATCH 025/183] 8150102: C1 should fold arraylength for constant/trusted arrays Reviewed-by: vlivanov, kvn --- hotspot/src/share/vm/c1/c1_Canonicalizer.cpp | 38 ++++++++++---------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp index e06aa581833..48b814531e4 100644 --- a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp +++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp @@ -222,29 +222,31 @@ void Canonicalizer::do_StoreField (StoreField* x) { } void Canonicalizer::do_ArrayLength (ArrayLength* x) { - NewArray* array = x->array()->as_NewArray(); - if (array != NULL && array->length() != NULL) { - Constant* length = array->length()->as_Constant(); - if (length != NULL) { - // do not use the Constant itself, but create a new Constant - // with same value Otherwise a Constant is live over multiple - // blocks without being registered in a state array. + NewArray* na; + Constant* ct; + + if ((na = x->array()->as_NewArray()) != NULL) { + // New arrays might have the known length. + // Do not use the Constant itself, but create a new Constant + // with same value Otherwise a Constant is live over multiple + // blocks without being registered in a state array. + Constant* length; + if (na->length() != NULL && + (length = na->length()->as_Constant()) != NULL) { assert(length->type()->as_IntConstant() != NULL, "array length must be integer"); set_constant(length->type()->as_IntConstant()->value()); } + + } else if ((ct = x->array()->as_Constant()) != NULL) { + // Constant arrays have constant lengths. + set_constant(ct->type()->as_ArrayConstant()->value()->length()); + +#ifdef ASSERT } else { LoadField* lf = x->array()->as_LoadField(); - if (lf != NULL) { - ciField* field = lf->field(); - if (field->is_constant() && field->is_static()) { - // final static field - ciObject* c = field->constant_value().as_object(); - if (c->is_array()) { - ciArray* array = (ciArray*) c; - set_constant(array->length()); - } - } - } + bool is_static_constant = (lf != NULL) && lf->field()->is_constant() && lf->field()->is_static(); + assert(!is_static_constant, "Constant field loads are folded during parsing"); +#endif // ASSERT } } From 36e011b2f09ce3e16cd4009156421b024e16fe89 Mon Sep 17 00:00:00 2001 From: Jamsheed Mohammed C M Date: Mon, 22 Feb 2016 23:37:29 -0800 Subject: [PATCH 026/183] 8145333: -XX:+EnableJVMCI -XX:+UseJVMCICompiler -XX:-EnableJVMCI makes JVM crash JVMCI Flags are checked for consistency after parse. Reviewed-by: twisti --- .../jvmci/commandLineFlagConstraintsJVMCI.cpp | 51 ----- .../jvmci/commandLineFlagConstraintsJVMCI.hpp | 40 ---- hotspot/src/share/vm/jvmci/jvmci_globals.cpp | 184 ++++++++++++++++++ hotspot/src/share/vm/jvmci/jvmci_globals.hpp | 21 +- hotspot/src/share/vm/runtime/arguments.cpp | 14 ++ hotspot/src/share/vm/runtime/arguments.hpp | 5 +- .../runtime/commandLineFlagConstraintList.cpp | 14 -- 7 files changed, 210 insertions(+), 119 deletions(-) delete mode 100644 hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp delete mode 100644 hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp diff --git a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp b/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp deleted file mode 100644 index 6481aaddca2..00000000000 --- a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2015, 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. - * - */ - -#include "precompiled.hpp" -#include "jvmci/commandLineFlagConstraintsJVMCI.hpp" -#include "runtime/arguments.hpp" -#include "runtime/globals.hpp" -#include "utilities/defaultStream.hpp" - -Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(bool value, bool verbose) { - if (!EnableJVMCI) { - if (verbose == true) { - jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); - } - return Flag::VIOLATES_CONSTRAINT; - } else { - return Flag::SUCCESS; - } -} - -Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(intx value, bool verbose) { - if (!EnableJVMCI) { - if (verbose == true) { - jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); - } - return Flag::VIOLATES_CONSTRAINT; - } else { - return Flag::SUCCESS; - } -} diff --git a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp b/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp deleted file mode 100644 index 35f47f9967d..00000000000 --- a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2015, 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. - * - */ - -#ifndef SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP -#define SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP - -#include "runtime/globals.hpp" -#include "utilities/globalDefinitions.hpp" - -/* - * Here we have JVMCI arguments constraints functions, which are called automatically - * whenever flag's value changes. If the constraint fails the function should return - * an appropriate error value. - */ - -Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(bool value, bool verbose); -Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(intx value, bool verbose); - -#endif /* SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP */ diff --git a/hotspot/src/share/vm/jvmci/jvmci_globals.cpp b/hotspot/src/share/vm/jvmci/jvmci_globals.cpp index f555863ed0d..992746975f4 100644 --- a/hotspot/src/share/vm/jvmci/jvmci_globals.cpp +++ b/hotspot/src/share/vm/jvmci/jvmci_globals.cpp @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "jvmci/jvmci_globals.hpp" +#include "utilities/defaultStream.hpp" +#include "runtime/globals_extension.hpp" JVMCI_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ MATERIALIZE_PD_DEVELOPER_FLAG, \ @@ -34,3 +36,185 @@ JVMCI_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ MATERIALIZE_NOTPRODUCT_FLAG, IGNORE_RANGE, \ IGNORE_CONSTRAINT) + +#define JVMCI_IGNORE_FLAG_FOUR_PARAM(type, name, value, doc) +#define JVMCI_IGNORE_FLAG_THREE_PARAM(type, name, doc) + +// Return true if jvmci flags are consistent. +bool JVMCIGlobals::check_jvmci_flags_are_consistent() { + if (EnableJVMCI) { + return true; + } + + // "FLAG_IS_DEFAULT" fail count. + int fail_count = 0; + // Number of "FLAG_IS_DEFAULT" fails that should be skipped before code + // detect real consistency failure. + int skip_fail_count; + + // EnableJVMCI flag is false here. + // If any other flag is changed, consistency check should fail. + // JVMCI_FLAGS macros added below can handle all JVMCI flags automatically. + // But it contains check for EnableJVMCI flag too, which is required to be + // skipped. This can't be handled easily! + // So the code looks for at-least two flag changes to detect consistency + // failure when EnableJVMCI flag is changed. + // Otherwise one flag change is sufficient to detect consistency failure. + // Set skip_fail_count to 0 if EnableJVMCI flag is default. + // Set skip_fail_count to 1 if EnableJVMCI flag is changed. + // This value will be used to skip fails in macro expanded code later. + if (!FLAG_IS_DEFAULT(EnableJVMCI)) { + skip_fail_count = 1; + } else { + skip_fail_count = 0; + } + +#define EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(FLAG) \ + if (!FLAG_IS_DEFAULT(FLAG)) { \ + fail_count++; \ + if (fail_count > skip_fail_count) { \ + return false; \ + } \ + } + +#define JVMCI_DIAGNOSTIC_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#define JVMCI_EXPERIMENTAL_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) + + // Check consistency of diagnostic flags if UnlockDiagnosticVMOptions is true + // or not default. UnlockDiagnosticVMOptions is default true in debug builds. + if (UnlockDiagnosticVMOptions || !FLAG_IS_DEFAULT(UnlockDiagnosticVMOptions)) { + JVMCI_FLAGS(JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_DIAGNOSTIC_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + } + + // Check consistency of experimental flags if UnlockExperimentalVMOptions is + // true or not default. + if (UnlockExperimentalVMOptions || !FLAG_IS_DEFAULT(UnlockExperimentalVMOptions)) { + JVMCI_FLAGS(JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_EXPERIMENTAL_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + } + +#ifndef PRODUCT +#define JVMCI_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#define JVMCI_PD_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#define JVMCI_NOTPRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#else +#define JVMCI_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) +#define JVMCI_PD_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, doc) +#define JVMCI_NOTPRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) +#endif + +#define JVMCI_PD_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#define JVMCI_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) + + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_PD_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_PD_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_NOTPRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + +#undef EMIT_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_PD_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_NOTPRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_DIAGNOSTIC_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_PD_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_EXPERIMENTAL_FLAG_VALUE_CHANGED_CHECK_CODE + + return true; +} + +// Print jvmci arguments inconsistency error message. +void JVMCIGlobals::print_jvmci_args_inconsistency_error_message() { + const char* error_msg = "Improperly specified VM option '%s'\n"; + jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); + +#define EMIT_CHECK_PRINT_ERR_MSG_CODE(FLAG) \ + if (!FLAG_IS_DEFAULT(FLAG)) { \ + if (strcmp(#FLAG, "EnableJVMCI")) { \ + jio_fprintf(defaultStream::error_stream(), error_msg, #FLAG); \ + } \ + } + +#define JVMCI_DIAGNOSTIC_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#define JVMCI_EXPERIMENTAL_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) + + if (UnlockDiagnosticVMOptions || !FLAG_IS_DEFAULT(UnlockDiagnosticVMOptions)) { + JVMCI_FLAGS(JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_DIAGNOSTIC_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + } + + if (UnlockExperimentalVMOptions || !FLAG_IS_DEFAULT(UnlockExperimentalVMOptions)) { + JVMCI_FLAGS(JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_EXPERIMENTAL_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + } + +#ifndef PRODUCT +#define JVMCI_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#define JVMCI_PD_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#define JVMCI_NOTPRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#else +#define JVMCI_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) +#define JVMCI_PD_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, doc) +#define JVMCI_NOTPRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) +#endif + +#define JVMCI_PD_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#define JVMCI_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) + + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_PD_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_PD_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_NOTPRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + +#undef EMIT_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_PD_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_NOTPRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_PD_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_DIAGNOSTIC_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_EXPERIMENTAL_FLAG_CHECK_PRINT_ERR_MSG_CODE + +} + +#undef JVMCI_IGNORE_FLAG_FOUR_PARAM +#undef JVMCI_IGNORE_FLAG_THREE_PARAM diff --git a/hotspot/src/share/vm/jvmci/jvmci_globals.hpp b/hotspot/src/share/vm/jvmci/jvmci_globals.hpp index ac1bfd119e6..03285e3bdfc 100644 --- a/hotspot/src/share/vm/jvmci/jvmci_globals.hpp +++ b/hotspot/src/share/vm/jvmci/jvmci_globals.hpp @@ -39,29 +39,23 @@ \ experimental(bool, UseJVMCICompiler, false, \ "Use JVMCI as the default compiler") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(bool, BootstrapJVMCI, false, \ "Bootstrap JVMCI before running Java main method") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(bool, PrintBootstrap, true, \ "Print JVMCI bootstrap progress and summary") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(intx, JVMCIThreads, 1, \ "Force number of JVMCI compiler threads to use") \ range(1, max_jint) \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(intx, JVMCIHostThreads, 1, \ "Force number of compiler threads for JVMCI host compiler") \ range(1, max_jint) \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(bool, CodeInstallSafepointChecks, true, \ "Perform explicit safepoint checks while installing code") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ NOT_COMPILER2(product(intx, MaxVectorSize, 64, \ "Max vector size in bytes, " \ @@ -74,28 +68,22 @@ "Trace level for JVMCI: " \ "1 means emit a message for each CompilerToVM call," \ "levels greater than 1 provide progressively greater detail") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(intx, JVMCICounterSize, 0, \ "Reserved size for benchmark counters") \ range(0, max_jint) \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(bool, JVMCICountersExcludeCompiler, true, \ "Exclude JVMCI compiler threads from benchmark counters") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ develop(bool, JVMCIUseFastLocking, true, \ "Use fast inlined locking code") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(intx, JVMCINMethodSizeLimit, (80*K)*wordSize, \ "Maximum size of a compiled method.") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ develop(bool, TraceUncollectedSpeculations, false, \ - "Print message when a failed speculation was not collected") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + "Print message when a failed speculation was not collected") // Read default values for JVMCI globals @@ -110,4 +98,11 @@ JVMCI_FLAGS(DECLARE_DEVELOPER_FLAG, \ IGNORE_RANGE, \ IGNORE_CONSTRAINT) +class JVMCIGlobals { + public: + // Return true if jvmci flags are consistent. + static bool check_jvmci_flags_are_consistent(); + // Print jvmci arguments inconsistency error message. + static void print_jvmci_args_inconsistency_error_message(); +}; #endif // SHARE_VM_JVMCI_JVMCIGLOBALS_HPP diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index fc891394d4a..3b335e39a36 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -2314,6 +2314,17 @@ bool Arguments::sun_java_launcher_is_altjvm() { //=========================================================================================================== // Parsing of main arguments +#if INCLUDE_JVMCI +// Check consistency of jvmci vm argument settings. +bool Arguments::check_jvmci_args_consistency() { + if (!EnableJVMCI && !JVMCIGlobals::check_jvmci_flags_are_consistent()) { + JVMCIGlobals::print_jvmci_args_inconsistency_error_message(); + return false; + } + return true; +} +#endif //INCLUDE_JVMCI + // Check consistency of GC selection bool Arguments::check_gc_consistency() { // Ensure that the user has not selected conflicting sets @@ -2410,6 +2421,9 @@ bool Arguments::check_vm_args_consistency() { #endif } #if INCLUDE_JVMCI + + status = status && check_jvmci_args_consistency(); + if (EnableJVMCI) { if (!ScavengeRootsInCode) { warning("forcing ScavengeRootsInCode non-zero because JVMCI is enabled"); diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index e7ce4f30cab..8fb95492c61 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -505,7 +505,10 @@ class Arguments : AllStatic { static void set_gc_specific_flags(); static inline bool gc_selected(); // whether a gc has been selected static void select_gc_ergonomically(); - +#if INCLUDE_JVMCI + // Check consistency of jvmci vm argument settings. + static bool check_jvmci_args_consistency(); +#endif // Check for consistency in the selection of the garbage collector. static bool check_gc_consistency(); // Check user-selected gc // Check consistency or otherwise of VM argument settings diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp index 60cf0daecc1..2f96660c260 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp @@ -33,9 +33,6 @@ #include "runtime/commandLineFlagConstraintsRuntime.hpp" #include "runtime/os.hpp" #include "utilities/macros.hpp" -#if INCLUDE_JVMCI -#include "jvmci/commandLineFlagConstraintsJVMCI.hpp" -#endif class CommandLineFlagConstraint_bool : public CommandLineFlagConstraint { CommandLineFlagConstraintFunc_bool _constraint; @@ -254,17 +251,6 @@ void CommandLineFlagConstraintList::init(void) { IGNORE_RANGE, EMIT_CONSTRAINT_CHECK)); -#if INCLUDE_JVMCI - emit_constraint_no(NULL JVMCI_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, - EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, - EMIT_CONSTRAINT_PRODUCT_FLAG, - EMIT_CONSTRAINT_PD_PRODUCT_FLAG, - EMIT_CONSTRAINT_DIAGNOSTIC_FLAG, - EMIT_CONSTRAINT_EXPERIMENTAL_FLAG, - EMIT_CONSTRAINT_NOTPRODUCT_FLAG, - IGNORE_RANGE, - EMIT_CONSTRAINT_CHECK)); -#endif // INCLUDE_JVMCI #ifdef COMPILER1 emit_constraint_no(NULL C1_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, From 0e31a18fd122d2fd9f97d8c34aef43f66c3cabee Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 23 Feb 2016 17:55:20 +0300 Subject: [PATCH 027/183] 8150180: String.value contents should be trusted Reviewed-by: vlivanov, redestad, jrose, twisti --- hotspot/src/share/vm/opto/library_call.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 753612c206f..f604d59a1ac 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -1584,6 +1584,13 @@ bool LibraryCallKit::inline_string_char_access(bool is_store) { assert (type2aelembytes(T_CHAR) == type2aelembytes(T_BYTE)*2, "sanity: byte[] and char[] scales agree"); + // Bail when getChar over constants is requested: constant folding would + // reject folding mismatched char access over byte[]. A normal inlining for getChar + // Java method would constant fold nicely instead. + if (!is_store && value->is_Con() && index->is_Con()) { + return false; + } + Node* adr = array_element_address(value, index, T_CHAR); if (is_store) { (void) store_to_memory(control(), adr, ch, T_CHAR, TypeAryPtr::BYTES, MemNode::unordered, From 744d73a67ff99438835465042ab18985f728335c Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 23 Feb 2016 17:18:31 +0100 Subject: [PATCH 028/183] 8148353: [linux-sparc] Crash in libawt.so on Linux SPARC Gcc expects clean 32 bit int in 64 bit register on function entry Reviewed-by: kvn, dlong --- hotspot/make/test/JtregNative.gmk | 1 + .../src/cpu/sparc/vm/sharedRuntime_sparc.cpp | 7 ++- .../test/compiler/native/TestDirtyInt.java | 46 +++++++++++++++++++ .../test/compiler/native/libTestDirtyInt.c | 33 +++++++++++++ 4 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 hotspot/test/compiler/native/TestDirtyInt.java create mode 100644 hotspot/test/compiler/native/libTestDirtyInt.c diff --git a/hotspot/make/test/JtregNative.gmk b/hotspot/make/test/JtregNative.gmk index 109c04d37fb..bced741d6a7 100644 --- a/hotspot/make/test/JtregNative.gmk +++ b/hotspot/make/test/JtregNative.gmk @@ -48,6 +48,7 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \ $(HOTSPOT_TOPDIR)/test/runtime/SameObject \ $(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \ $(HOTSPOT_TOPDIR)/test/compiler/calls \ + $(HOTSPOT_TOPDIR)/test/compiler/native \ # # Add conditional directories here when needed. diff --git a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index da9869fdb4d..65cbf6e8315 100644 --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -1349,9 +1349,12 @@ static void move32_64(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { } } else if (dst.first()->is_stack()) { // reg to stack - __ st_ptr(src.first()->as_Register(), SP, reg2offset(dst.first()) + STACK_BIAS); + // Some compilers (gcc) expect a clean 32 bit value on function entry + __ signx(src.first()->as_Register(), L5); + __ st_ptr(L5, SP, reg2offset(dst.first()) + STACK_BIAS); } else { - __ mov(src.first()->as_Register(), dst.first()->as_Register()); + // Some compilers (gcc) expect a clean 32 bit value on function entry + __ signx(src.first()->as_Register(), dst.first()->as_Register()); } } diff --git a/hotspot/test/compiler/native/TestDirtyInt.java b/hotspot/test/compiler/native/TestDirtyInt.java new file mode 100644 index 00000000000..607fd2d491c --- /dev/null +++ b/hotspot/test/compiler/native/TestDirtyInt.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @run main/native TestDirtyInt + */ +public class TestDirtyInt { + static { + System.loadLibrary("TestDirtyInt"); + } + + native static int test(int v); + + static int compiled(int v) { + return test(v<<2); + } + + static public void main(String[] args) { + for (int i = 0; i < 20000; i++) { + int res = compiled(Integer.MAX_VALUE); + if (res != 0x42) { + throw new RuntimeException("Test failed"); + } + } + } +} diff --git a/hotspot/test/compiler/native/libTestDirtyInt.c b/hotspot/test/compiler/native/libTestDirtyInt.c new file mode 100644 index 00000000000..b688a369398 --- /dev/null +++ b/hotspot/test/compiler/native/libTestDirtyInt.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016, 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. + */ + +#include "jni.h" +#include + +static int array = 0x42; + +JNIEXPORT jint JNICALL Java_TestDirtyInt_test(JNIEnv* env, jclass jclazz, jint v) +{ + int* ptr = &array + v + 4; + return *ptr; +} From 449c65bf50107d92f18c7ebbefd2aec4979febc3 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 23 Feb 2016 17:59:27 +0100 Subject: [PATCH 029/183] 8007986: GrowableArray should implement binary search Binary search method for GrowableArray Reviewed-by: vlivanov, jrose --- .../src/share/vm/ci/ciConstantPoolCache.cpp | 49 ++++-------- .../src/share/vm/ci/ciConstantPoolCache.hpp | 2 +- hotspot/src/share/vm/ci/ciObjectFactory.cpp | 73 ++++-------------- hotspot/src/share/vm/ci/ciObjectFactory.hpp | 4 +- hotspot/src/share/vm/opto/compile.cpp | 75 ++++++++----------- hotspot/src/share/vm/opto/compile.hpp | 2 +- .../src/share/vm/utilities/growableArray.hpp | 2 +- 7 files changed, 62 insertions(+), 145 deletions(-) diff --git a/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp b/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp index 6ceacdc5a5a..b67450bf026 100644 --- a/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp +++ b/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp @@ -41,58 +41,37 @@ ciConstantPoolCache::ciConstantPoolCache(Arena* arena, _keys = new (arena) GrowableArray(arena, expected_size, 0, 0); } +int ciConstantPoolCache::key_compare(const int& key, const int& elt) { + if (key < elt) return -1; + else if (key > elt) return 1; + else return 0; +} + // ------------------------------------------------------------------ // ciConstantPoolCache::get // // Get the entry at some index void* ciConstantPoolCache::get(int index) { ASSERT_IN_VM; - int pos = find(index); - if (pos >= _keys->length() || - _keys->at(pos) != index) { + bool found = false; + int pos = _keys->find_sorted(index, found); + if (!found) { // This element is not present in the cache. return NULL; } return _elements->at(pos); } -// ------------------------------------------------------------------ -// ciConstantPoolCache::find -// -// Use binary search to find the position of this index in the cache. -// If there is no entry in the cache corresponding to this oop, return -// the position at which the index would be inserted. -int ciConstantPoolCache::find(int key) { - int min = 0; - int max = _keys->length()-1; - - while (max >= min) { - int mid = (max + min) / 2; - int value = _keys->at(mid); - if (value < key) { - min = mid + 1; - } else if (value > key) { - max = mid - 1; - } else { - return mid; - } - } - return min; -} - // ------------------------------------------------------------------ // ciConstantPoolCache::insert // // Insert a ciObject into the table at some index. void ciConstantPoolCache::insert(int index, void* elem) { - int i; - int pos = find(index); - for (i = _keys->length()-1; i >= pos; i--) { - _keys->at_put_grow(i+1, _keys->at(i)); - _elements->at_put_grow(i+1, _elements->at(i)); - } - _keys->at_put_grow(pos, index); - _elements->at_put_grow(pos, elem); + bool found = false; + int pos = _keys->find_sorted(index, found); + assert(!found, "duplicate"); + _keys->insert_before(pos, index); + _elements->insert_before(pos, elem); } // ------------------------------------------------------------------ diff --git a/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp b/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp index 17cf77681e0..8c726a0154f 100644 --- a/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp +++ b/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp @@ -38,7 +38,7 @@ private: GrowableArray* _keys; GrowableArray* _elements; - int find(int index); + static int key_compare(const int& key, const int& elt); public: ciConstantPoolCache(Arena* arena, int expected_size); diff --git a/hotspot/src/share/vm/ci/ciObjectFactory.cpp b/hotspot/src/share/vm/ci/ciObjectFactory.cpp index 240ed839bf0..bcb7540a3e9 100644 --- a/hotspot/src/share/vm/ci/ciObjectFactory.cpp +++ b/hotspot/src/share/vm/ci/ciObjectFactory.cpp @@ -260,6 +260,13 @@ ciObject* ciObjectFactory::get(oop key) { return new_object; } +int ciObjectFactory::metadata_compare(Metadata* const& key, ciMetadata* const& elt) { + Metadata* value = elt->constant_encoding(); + if (key < value) return -1; + else if (key > value) return 1; + else return 0; +} + // ------------------------------------------------------------------ // ciObjectFactory::get_metadata // @@ -280,7 +287,8 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) { } #endif // ASSERT int len = _ci_metadata->length(); - int index = find(key, _ci_metadata); + bool found = false; + int index = _ci_metadata->find_sorted(key, found); #ifdef ASSERT if (CIObjectFactoryVerify) { for (int i=0; i<_ci_metadata->length(); i++) { @@ -290,7 +298,8 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) { } } #endif - if (!is_found_at(index, key, _ci_metadata)) { + + if (!found) { // The ciMetadata does not yet exist. Create it and insert it // into the cache. ciMetadata* new_object = create_new_metadata(key); @@ -300,10 +309,10 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) { if (len != _ci_metadata->length()) { // creating the new object has recursively entered new objects // into the table. We need to recompute our index. - index = find(key, _ci_metadata); + index = _ci_metadata->find_sorted(key, found); } - assert(!is_found_at(index, key, _ci_metadata), "no double insert"); - insert(index, new_object, _ci_metadata); + assert(!found, "no double insert"); + _ci_metadata->insert_before(index, new_object); return new_object; } return _ci_metadata->at(index)->as_metadata(); @@ -655,60 +664,6 @@ void ciObjectFactory::init_ident_of(ciBaseObject* obj) { obj->set_ident(_next_ident++); } -// ------------------------------------------------------------------ -// ciObjectFactory::find -// -// Use binary search to find the position of this oop in the cache. -// If there is no entry in the cache corresponding to this oop, return -// the position at which the oop should be inserted. -int ciObjectFactory::find(Metadata* key, GrowableArray* objects) { - int min = 0; - int max = objects->length()-1; - - // print_contents(); - - while (max >= min) { - int mid = (max + min) / 2; - Metadata* value = objects->at(mid)->constant_encoding(); - if (value < key) { - min = mid + 1; - } else if (value > key) { - max = mid - 1; - } else { - return mid; - } - } - return min; -} - -// ------------------------------------------------------------------ -// ciObjectFactory::is_found_at -// -// Verify that the binary seach found the given key. -bool ciObjectFactory::is_found_at(int index, Metadata* key, GrowableArray* objects) { - return (index < objects->length() && - objects->at(index)->constant_encoding() == key); -} - - -// ------------------------------------------------------------------ -// ciObjectFactory::insert -// -// Insert a ciObject into the table at some index. -void ciObjectFactory::insert(int index, ciMetadata* obj, GrowableArray* objects) { - int len = objects->length(); - if (len == index) { - objects->append(obj); - } else { - objects->append(objects->at(len-1)); - int pos; - for (pos = len-2; pos >= index; pos--) { - objects->at_put(pos+1,objects->at(pos)); - } - objects->at_put(index, obj); - } -} - static ciObjectFactory::NonPermObject* emptyBucket = NULL; // ------------------------------------------------------------------ diff --git a/hotspot/src/share/vm/ci/ciObjectFactory.hpp b/hotspot/src/share/vm/ci/ciObjectFactory.hpp index 4cdcc69beac..4f0cbd7ac73 100644 --- a/hotspot/src/share/vm/ci/ciObjectFactory.hpp +++ b/hotspot/src/share/vm/ci/ciObjectFactory.hpp @@ -68,9 +68,7 @@ private: NonPermObject* _non_perm_bucket[NON_PERM_BUCKETS]; int _non_perm_count; - int find(Metadata* key, GrowableArray* objects); - bool is_found_at(int index, Metadata* key, GrowableArray* objects); - void insert(int index, ciMetadata* obj, GrowableArray* objects); + static int metadata_compare(Metadata* const& key, ciMetadata* const& elt); ciObject* create_new_object(oop o); ciMetadata* create_new_metadata(Metadata* o); diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index bf5597753b6..6e3e46d790f 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -88,7 +88,27 @@ MachConstantBaseNode* Compile::mach_constant_base_node() { // Return the index at which m must be inserted (or already exists). // The sort order is by the address of the ciMethod, with is_virtual as minor key. -int Compile::intrinsic_insertion_index(ciMethod* m, bool is_virtual) { +class IntrinsicDescPair { + private: + ciMethod* _m; + bool _is_virtual; + public: + IntrinsicDescPair(ciMethod* m, bool is_virtual) : _m(m), _is_virtual(is_virtual) {} + static int compare(IntrinsicDescPair* const& key, CallGenerator* const& elt) { + ciMethod* m= elt->method(); + ciMethod* key_m = key->_m; + if (key_m < m) return -1; + else if (key_m > m) return 1; + else { + bool is_virtual = elt->is_virtual(); + bool key_virtual = key->_is_virtual; + if (key_virtual < is_virtual) return -1; + else if (key_virtual > is_virtual) return 1; + else return 0; + } + } +}; +int Compile::intrinsic_insertion_index(ciMethod* m, bool is_virtual, bool& found) { #ifdef ASSERT for (int i = 1; i < _intrinsics->length(); i++) { CallGenerator* cg1 = _intrinsics->at(i-1); @@ -99,63 +119,28 @@ int Compile::intrinsic_insertion_index(ciMethod* m, bool is_virtual) { "compiler intrinsics list must stay sorted"); } #endif - // Binary search sorted list, in decreasing intervals [lo, hi]. - int lo = 0, hi = _intrinsics->length()-1; - while (lo <= hi) { - int mid = (uint)(hi + lo) / 2; - ciMethod* mid_m = _intrinsics->at(mid)->method(); - if (m < mid_m) { - hi = mid-1; - } else if (m > mid_m) { - lo = mid+1; - } else { - // look at minor sort key - bool mid_virt = _intrinsics->at(mid)->is_virtual(); - if (is_virtual < mid_virt) { - hi = mid-1; - } else if (is_virtual > mid_virt) { - lo = mid+1; - } else { - return mid; // exact match - } - } - } - return lo; // inexact match + IntrinsicDescPair pair(m, is_virtual); + return _intrinsics->find_sorted(&pair, found); } void Compile::register_intrinsic(CallGenerator* cg) { if (_intrinsics == NULL) { _intrinsics = new (comp_arena())GrowableArray(comp_arena(), 60, 0, NULL); } - // This code is stolen from ciObjectFactory::insert. - // Really, GrowableArray should have methods for - // insert_at, remove_at, and binary_search. int len = _intrinsics->length(); - int index = intrinsic_insertion_index(cg->method(), cg->is_virtual()); - if (index == len) { - _intrinsics->append(cg); - } else { -#ifdef ASSERT - CallGenerator* oldcg = _intrinsics->at(index); - assert(oldcg->method() != cg->method() || oldcg->is_virtual() != cg->is_virtual(), "don't register twice"); -#endif - _intrinsics->append(_intrinsics->at(len-1)); - int pos; - for (pos = len-2; pos >= index; pos--) { - _intrinsics->at_put(pos+1,_intrinsics->at(pos)); - } - _intrinsics->at_put(index, cg); - } + bool found = false; + int index = intrinsic_insertion_index(cg->method(), cg->is_virtual(), found); + assert(!found, "registering twice"); + _intrinsics->insert_before(index, cg); assert(find_intrinsic(cg->method(), cg->is_virtual()) == cg, "registration worked"); } CallGenerator* Compile::find_intrinsic(ciMethod* m, bool is_virtual) { assert(m->is_loaded(), "don't try this on unloaded methods"); if (_intrinsics != NULL) { - int index = intrinsic_insertion_index(m, is_virtual); - if (index < _intrinsics->length() - && _intrinsics->at(index)->method() == m - && _intrinsics->at(index)->is_virtual() == is_virtual) { + bool found = false; + int index = intrinsic_insertion_index(m, is_virtual, found); + if (found) { return _intrinsics->at(index); } } diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp index 871abe245a7..40724fbd6b7 100644 --- a/hotspot/src/share/vm/opto/compile.hpp +++ b/hotspot/src/share/vm/opto/compile.hpp @@ -1250,7 +1250,7 @@ class Compile : public Phase { // Intrinsic setup. void register_library_intrinsics(); // initializer CallGenerator* make_vm_intrinsic(ciMethod* m, bool is_virtual); // constructor - int intrinsic_insertion_index(ciMethod* m, bool is_virtual); // helper + int intrinsic_insertion_index(ciMethod* m, bool is_virtual, bool& found); // helper CallGenerator* find_intrinsic(ciMethod* m, bool is_virtual); // query fn void register_intrinsic(CallGenerator* cg); // update fn diff --git a/hotspot/src/share/vm/utilities/growableArray.hpp b/hotspot/src/share/vm/utilities/growableArray.hpp index 933cf339661..a2780fecca5 100644 --- a/hotspot/src/share/vm/utilities/growableArray.hpp +++ b/hotspot/src/share/vm/utilities/growableArray.hpp @@ -396,7 +396,7 @@ template class GrowableArray : public GenericGrowableArray { int max = length() - 1; while (max >= min) { - int mid = (max + min) / 2; + int mid = (int)(((uint)max + min) / 2); E value = at(mid); int diff = compare(key, value); if (diff > 0) { From 0c43809cfe25a4d07d9765a9f2ccb4b00c7d089f Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 23 Feb 2016 22:09:41 +0300 Subject: [PATCH 030/183] 8148146: Integrate new internal Unsafe entry points, and basic intrinsic support for VarHandles Reviewed-by: psandoz, kvn, jrose, adinn, simonis, coleenp --- hotspot/src/cpu/x86/vm/x86_32.ad | 28 + hotspot/src/cpu/x86/vm/x86_64.ad | 81 ++ hotspot/src/share/vm/adlc/formssel.cpp | 2 + hotspot/src/share/vm/classfile/vmSymbols.cpp | 56 +- hotspot/src/share/vm/classfile/vmSymbols.hpp | 138 +++- hotspot/src/share/vm/opto/c2compiler.cpp | 95 ++- hotspot/src/share/vm/opto/classes.hpp | 8 + hotspot/src/share/vm/opto/compile.cpp | 8 + hotspot/src/share/vm/opto/escape.cpp | 8 + hotspot/src/share/vm/opto/library_call.cpp | 765 ++++++++++++------ hotspot/src/share/vm/opto/loopTransform.cpp | 8 + hotspot/src/share/vm/opto/matcher.cpp | 16 + hotspot/src/share/vm/opto/memnode.hpp | 107 ++- hotspot/src/share/vm/opto/node.hpp | 5 + hotspot/src/share/vm/prims/unsafe.cpp | 42 + hotspot/src/share/vm/runtime/vmStructs.cpp | 18 +- ...dkInternalMiscUnsafeAccessTestBoolean.java | 14 + .../JdkInternalMiscUnsafeAccessTestByte.java | 14 + .../JdkInternalMiscUnsafeAccessTestChar.java | 14 + ...JdkInternalMiscUnsafeAccessTestDouble.java | 14 + .../JdkInternalMiscUnsafeAccessTestFloat.java | 14 + .../JdkInternalMiscUnsafeAccessTestInt.java | 78 ++ .../JdkInternalMiscUnsafeAccessTestLong.java | 78 ++ ...JdkInternalMiscUnsafeAccessTestObject.java | 78 ++ .../JdkInternalMiscUnsafeAccessTestShort.java | 14 + .../unsafe/X-UnsafeAccessTest.java.template | 85 +- .../compiler/unsafe/generate-unsafe-tests.sh | 97 +++ 27 files changed, 1590 insertions(+), 295 deletions(-) create mode 100644 hotspot/test/compiler/unsafe/generate-unsafe-tests.sh diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index f684cd5b5cd..b09ca8e36ab 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -7236,6 +7236,7 @@ instruct storeLConditional( memory mem, eADXRegL oldval, eBCXRegL newval, eFlags instruct compareAndSwapL( rRegI res, eSIRegP mem_ptr, eADXRegL oldval, eBCXRegL newval, eFlagsReg cr ) %{ predicate(VM_Version::supports_cx8()); match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapL mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "CMPXCHG8 [$mem_ptr],$newval\t# If EDX:EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" "MOV $res,0\n\t" @@ -7249,6 +7250,7 @@ instruct compareAndSwapL( rRegI res, eSIRegP mem_ptr, eADXRegL oldval, eBCXRegL instruct compareAndSwapP( rRegI res, pRegP mem_ptr, eAXRegP oldval, eCXRegP newval, eFlagsReg cr) %{ match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "CMPXCHG [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" "MOV $res,0\n\t" @@ -7261,6 +7263,7 @@ instruct compareAndSwapP( rRegI res, pRegP mem_ptr, eAXRegP oldval, eCXRegP new instruct compareAndSwapI( rRegI res, pRegP mem_ptr, eAXRegI oldval, eCXRegI newval, eFlagsReg cr) %{ match(Set res (CompareAndSwapI mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapI mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "CMPXCHG [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" "MOV $res,0\n\t" @@ -7271,6 +7274,31 @@ instruct compareAndSwapI( rRegI res, pRegP mem_ptr, eAXRegI oldval, eCXRegI newv ins_pipe( pipe_cmpxchg ); %} +instruct compareAndExchangeL( eSIRegP mem_ptr, eADXRegL oldval, eBCXRegL newval, eFlagsReg cr ) %{ + predicate(VM_Version::supports_cx8()); + match(Set oldval (CompareAndExchangeL mem_ptr (Binary oldval newval))); + effect(KILL cr); + format %{ "CMPXCHG8 [$mem_ptr],$newval\t# If EDX:EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" %} + ins_encode( enc_cmpxchg8(mem_ptr) ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeP( pRegP mem_ptr, eAXRegP oldval, eCXRegP newval, eFlagsReg cr) %{ + match(Set oldval (CompareAndExchangeP mem_ptr (Binary oldval newval))); + effect(KILL cr); + format %{ "CMPXCHG [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" %} + ins_encode( enc_cmpxchg(mem_ptr) ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeI( pRegP mem_ptr, eAXRegI oldval, eCXRegI newval, eFlagsReg cr) %{ + match(Set oldval (CompareAndExchangeI mem_ptr (Binary oldval newval))); + effect(KILL cr); + format %{ "CMPXCHG [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" %} + ins_encode( enc_cmpxchg(mem_ptr) ); + ins_pipe( pipe_cmpxchg ); +%} + instruct xaddI_no_res( memory mem, Universe dummy, immI add, eFlagsReg cr) %{ predicate(n->as_LoadStore()->result_not_used()); match(Set dummy (GetAndAddI mem add)); diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index 455354834ea..6f32ace2f18 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -7281,6 +7281,7 @@ instruct compareAndSwapP(rRegI res, %{ predicate(VM_Version::supports_cx8()); match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "cmpxchgq $mem_ptr,$newval\t# " @@ -7305,6 +7306,7 @@ instruct compareAndSwapL(rRegI res, %{ predicate(VM_Version::supports_cx8()); match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapL mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "cmpxchgq $mem_ptr,$newval\t# " @@ -7328,6 +7330,7 @@ instruct compareAndSwapI(rRegI res, rFlagsReg cr) %{ match(Set res (CompareAndSwapI mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapI mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "cmpxchgl $mem_ptr,$newval\t# " @@ -7351,6 +7354,7 @@ instruct compareAndSwapN(rRegI res, rax_RegN oldval, rRegN newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "cmpxchgl $mem_ptr,$newval\t# " @@ -7368,6 +7372,83 @@ instruct compareAndSwapN(rRegI res, ins_pipe( pipe_cmpxchg ); %} +instruct compareAndExchangeI( + memory mem_ptr, + rax_RegI oldval, rRegI newval, + rFlagsReg cr) +%{ + match(Set oldval (CompareAndExchangeI mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgl $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + opcode(0x0F, 0xB1); + ins_encode(lock_prefix, + REX_reg_mem(newval, mem_ptr), + OpcP, OpcS, + reg_mem(newval, mem_ptr) // lock cmpxchg + ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeL( + memory mem_ptr, + rax_RegL oldval, rRegL newval, + rFlagsReg cr) +%{ + predicate(VM_Version::supports_cx8()); + match(Set oldval (CompareAndExchangeL mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgq $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + opcode(0x0F, 0xB1); + ins_encode(lock_prefix, + REX_reg_mem_wide(newval, mem_ptr), + OpcP, OpcS, + reg_mem(newval, mem_ptr) // lock cmpxchg + ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeN( + memory mem_ptr, + rax_RegN oldval, rRegN newval, + rFlagsReg cr) %{ + match(Set oldval (CompareAndExchangeN mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgl $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + opcode(0x0F, 0xB1); + ins_encode(lock_prefix, + REX_reg_mem(newval, mem_ptr), + OpcP, OpcS, + reg_mem(newval, mem_ptr) // lock cmpxchg + ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeP( + memory mem_ptr, + rax_RegP oldval, rRegP newval, + rFlagsReg cr) +%{ + predicate(VM_Version::supports_cx8()); + match(Set oldval (CompareAndExchangeP mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgq $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + opcode(0x0F, 0xB1); + ins_encode(lock_prefix, + REX_reg_mem_wide(newval, mem_ptr), + OpcP, OpcS, + reg_mem(newval, mem_ptr) // lock cmpxchg + ); + ins_pipe( pipe_cmpxchg ); +%} + instruct xaddI_no_res( memory mem, Universe dummy, immI add, rFlagsReg cr) %{ predicate(n->as_LoadStore()->result_not_used()); match(Set dummy (GetAndAddI mem add)); diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp index d408c904c6c..a3faa48e426 100644 --- a/hotspot/src/share/vm/adlc/formssel.cpp +++ b/hotspot/src/share/vm/adlc/formssel.cpp @@ -3491,6 +3491,8 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const { "LoadPLocked", "StorePConditional", "StoreIConditional", "StoreLConditional", "CompareAndSwapI", "CompareAndSwapL", "CompareAndSwapP", "CompareAndSwapN", + "WeakCompareAndSwapI", "WeakCompareAndSwapL", "WeakCompareAndSwapP", "WeakCompareAndSwapN", + "CompareAndExchangeI", "CompareAndExchangeL", "CompareAndExchangeP", "CompareAndExchangeN", "StoreCM", "ClearArray", "GetAndAddI", "GetAndSetI", "GetAndSetP", diff --git a/hotspot/src/share/vm/classfile/vmSymbols.cpp b/hotspot/src/share/vm/classfile/vmSymbols.cpp index 81dda6e4fd0..1a5fe2a05fd 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.cpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp @@ -544,6 +544,42 @@ bool vmIntrinsics::is_disabled_by_flags(const methodHandle& method) { case vmIntrinsics::_putLongVolatile: case vmIntrinsics::_putFloatVolatile: case vmIntrinsics::_putDoubleVolatile: + case vmIntrinsics::_getObjectAcquire: + case vmIntrinsics::_getBooleanAcquire: + case vmIntrinsics::_getByteAcquire: + case vmIntrinsics::_getShortAcquire: + case vmIntrinsics::_getCharAcquire: + case vmIntrinsics::_getIntAcquire: + case vmIntrinsics::_getLongAcquire: + case vmIntrinsics::_getFloatAcquire: + case vmIntrinsics::_getDoubleAcquire: + case vmIntrinsics::_putObjectRelease: + case vmIntrinsics::_putBooleanRelease: + case vmIntrinsics::_putByteRelease: + case vmIntrinsics::_putShortRelease: + case vmIntrinsics::_putCharRelease: + case vmIntrinsics::_putIntRelease: + case vmIntrinsics::_putLongRelease: + case vmIntrinsics::_putFloatRelease: + case vmIntrinsics::_putDoubleRelease: + case vmIntrinsics::_getObjectOpaque: + case vmIntrinsics::_getBooleanOpaque: + case vmIntrinsics::_getByteOpaque: + case vmIntrinsics::_getShortOpaque: + case vmIntrinsics::_getCharOpaque: + case vmIntrinsics::_getIntOpaque: + case vmIntrinsics::_getLongOpaque: + case vmIntrinsics::_getFloatOpaque: + case vmIntrinsics::_getDoubleOpaque: + case vmIntrinsics::_putObjectOpaque: + case vmIntrinsics::_putBooleanOpaque: + case vmIntrinsics::_putByteOpaque: + case vmIntrinsics::_putShortOpaque: + case vmIntrinsics::_putCharOpaque: + case vmIntrinsics::_putIntOpaque: + case vmIntrinsics::_putLongOpaque: + case vmIntrinsics::_putFloatOpaque: + case vmIntrinsics::_putDoubleOpaque: case vmIntrinsics::_getByte_raw: case vmIntrinsics::_getShort_raw: case vmIntrinsics::_getChar_raw: @@ -569,9 +605,27 @@ bool vmIntrinsics::is_disabled_by_flags(const methodHandle& method) { case vmIntrinsics::_loadFence: case vmIntrinsics::_storeFence: case vmIntrinsics::_fullFence: - case vmIntrinsics::_compareAndSwapObject: case vmIntrinsics::_compareAndSwapLong: + case vmIntrinsics::_weakCompareAndSwapLong: + case vmIntrinsics::_weakCompareAndSwapLongAcquire: + case vmIntrinsics::_weakCompareAndSwapLongRelease: case vmIntrinsics::_compareAndSwapInt: + case vmIntrinsics::_weakCompareAndSwapInt: + case vmIntrinsics::_weakCompareAndSwapIntAcquire: + case vmIntrinsics::_weakCompareAndSwapIntRelease: + case vmIntrinsics::_compareAndSwapObject: + case vmIntrinsics::_weakCompareAndSwapObject: + case vmIntrinsics::_weakCompareAndSwapObjectAcquire: + case vmIntrinsics::_weakCompareAndSwapObjectRelease: + case vmIntrinsics::_compareAndExchangeIntVolatile: + case vmIntrinsics::_compareAndExchangeIntAcquire: + case vmIntrinsics::_compareAndExchangeIntRelease: + case vmIntrinsics::_compareAndExchangeLongVolatile: + case vmIntrinsics::_compareAndExchangeLongAcquire: + case vmIntrinsics::_compareAndExchangeLongRelease: + case vmIntrinsics::_compareAndExchangeObjectVolatile: + case vmIntrinsics::_compareAndExchangeObjectAcquire: + case vmIntrinsics::_compareAndExchangeObjectRelease: if (!InlineUnsafeOps) return true; break; case vmIntrinsics::_getShortUnaligned: diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 626009f4c2f..4cce6873268 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -1146,6 +1146,64 @@ do_intrinsic(_putFloatVolatile, jdk_internal_misc_Unsafe, putFloatVolatile_name, putFloat_signature, F_RN) \ do_intrinsic(_putDoubleVolatile, jdk_internal_misc_Unsafe, putDoubleVolatile_name, putDouble_signature, F_RN) \ \ + do_name(getObjectOpaque_name,"getObjectOpaque") do_name(putObjectOpaque_name,"putObjectOpaque") \ + do_name(getBooleanOpaque_name,"getBooleanOpaque") do_name(putBooleanOpaque_name,"putBooleanOpaque") \ + do_name(getByteOpaque_name,"getByteOpaque") do_name(putByteOpaque_name,"putByteOpaque") \ + do_name(getShortOpaque_name,"getShortOpaque") do_name(putShortOpaque_name,"putShortOpaque") \ + do_name(getCharOpaque_name,"getCharOpaque") do_name(putCharOpaque_name,"putCharOpaque") \ + do_name(getIntOpaque_name,"getIntOpaque") do_name(putIntOpaque_name,"putIntOpaque") \ + do_name(getLongOpaque_name,"getLongOpaque") do_name(putLongOpaque_name,"putLongOpaque") \ + do_name(getFloatOpaque_name,"getFloatOpaque") do_name(putFloatOpaque_name,"putFloatOpaque") \ + do_name(getDoubleOpaque_name,"getDoubleOpaque") do_name(putDoubleOpaque_name,"putDoubleOpaque") \ + \ + do_intrinsic(_getObjectOpaque, jdk_internal_misc_Unsafe, getObjectOpaque_name, getObject_signature, F_R) \ + do_intrinsic(_getBooleanOpaque, jdk_internal_misc_Unsafe, getBooleanOpaque_name, getBoolean_signature, F_R) \ + do_intrinsic(_getByteOpaque, jdk_internal_misc_Unsafe, getByteOpaque_name, getByte_signature, F_R) \ + do_intrinsic(_getShortOpaque, jdk_internal_misc_Unsafe, getShortOpaque_name, getShort_signature, F_R) \ + do_intrinsic(_getCharOpaque, jdk_internal_misc_Unsafe, getCharOpaque_name, getChar_signature, F_R) \ + do_intrinsic(_getIntOpaque, jdk_internal_misc_Unsafe, getIntOpaque_name, getInt_signature, F_R) \ + do_intrinsic(_getLongOpaque, jdk_internal_misc_Unsafe, getLongOpaque_name, getLong_signature, F_R) \ + do_intrinsic(_getFloatOpaque, jdk_internal_misc_Unsafe, getFloatOpaque_name, getFloat_signature, F_R) \ + do_intrinsic(_getDoubleOpaque, jdk_internal_misc_Unsafe, getDoubleOpaque_name, getDouble_signature, F_R) \ + do_intrinsic(_putObjectOpaque, jdk_internal_misc_Unsafe, putObjectOpaque_name, putObject_signature, F_R) \ + do_intrinsic(_putBooleanOpaque, jdk_internal_misc_Unsafe, putBooleanOpaque_name, putBoolean_signature, F_R) \ + do_intrinsic(_putByteOpaque, jdk_internal_misc_Unsafe, putByteOpaque_name, putByte_signature, F_R) \ + do_intrinsic(_putShortOpaque, jdk_internal_misc_Unsafe, putShortOpaque_name, putShort_signature, F_R) \ + do_intrinsic(_putCharOpaque, jdk_internal_misc_Unsafe, putCharOpaque_name, putChar_signature, F_R) \ + do_intrinsic(_putIntOpaque, jdk_internal_misc_Unsafe, putIntOpaque_name, putInt_signature, F_R) \ + do_intrinsic(_putLongOpaque, jdk_internal_misc_Unsafe, putLongOpaque_name, putLong_signature, F_R) \ + do_intrinsic(_putFloatOpaque, jdk_internal_misc_Unsafe, putFloatOpaque_name, putFloat_signature, F_R) \ + do_intrinsic(_putDoubleOpaque, jdk_internal_misc_Unsafe, putDoubleOpaque_name, putDouble_signature, F_R) \ + \ + do_name(getObjectAcquire_name, "getObjectAcquire") do_name(putObjectRelease_name, "putObjectRelease") \ + do_name(getBooleanAcquire_name, "getBooleanAcquire") do_name(putBooleanRelease_name, "putBooleanRelease") \ + do_name(getByteAcquire_name, "getByteAcquire") do_name(putByteRelease_name, "putByteRelease") \ + do_name(getShortAcquire_name, "getShortAcquire") do_name(putShortRelease_name, "putShortRelease") \ + do_name(getCharAcquire_name, "getCharAcquire") do_name(putCharRelease_name, "putCharRelease") \ + do_name(getIntAcquire_name, "getIntAcquire") do_name(putIntRelease_name, "putIntRelease") \ + do_name(getLongAcquire_name, "getLongAcquire") do_name(putLongRelease_name, "putLongRelease") \ + do_name(getFloatAcquire_name, "getFloatAcquire") do_name(putFloatRelease_name, "putFloatRelease") \ + do_name(getDoubleAcquire_name, "getDoubleAcquire") do_name(putDoubleRelease_name, "putDoubleRelease") \ + \ + do_intrinsic(_getObjectAcquire, jdk_internal_misc_Unsafe, getObjectAcquire_name, getObject_signature, F_R) \ + do_intrinsic(_getBooleanAcquire, jdk_internal_misc_Unsafe, getBooleanAcquire_name, getBoolean_signature, F_R) \ + do_intrinsic(_getByteAcquire, jdk_internal_misc_Unsafe, getByteAcquire_name, getByte_signature, F_R) \ + do_intrinsic(_getShortAcquire, jdk_internal_misc_Unsafe, getShortAcquire_name, getShort_signature, F_R) \ + do_intrinsic(_getCharAcquire, jdk_internal_misc_Unsafe, getCharAcquire_name, getChar_signature, F_R) \ + do_intrinsic(_getIntAcquire, jdk_internal_misc_Unsafe, getIntAcquire_name, getInt_signature, F_R) \ + do_intrinsic(_getLongAcquire, jdk_internal_misc_Unsafe, getLongAcquire_name, getLong_signature, F_R) \ + do_intrinsic(_getFloatAcquire, jdk_internal_misc_Unsafe, getFloatAcquire_name, getFloat_signature, F_R) \ + do_intrinsic(_getDoubleAcquire, jdk_internal_misc_Unsafe, getDoubleAcquire_name, getDouble_signature, F_R) \ + do_intrinsic(_putObjectRelease, jdk_internal_misc_Unsafe, putObjectRelease_name, putObject_signature, F_R) \ + do_intrinsic(_putBooleanRelease, jdk_internal_misc_Unsafe, putBooleanRelease_name, putBoolean_signature, F_R) \ + do_intrinsic(_putByteRelease, jdk_internal_misc_Unsafe, putByteRelease_name, putByte_signature, F_R) \ + do_intrinsic(_putShortRelease, jdk_internal_misc_Unsafe, putShortRelease_name, putShort_signature, F_R) \ + do_intrinsic(_putCharRelease, jdk_internal_misc_Unsafe, putCharRelease_name, putChar_signature, F_R) \ + do_intrinsic(_putIntRelease, jdk_internal_misc_Unsafe, putIntRelease_name, putInt_signature, F_R) \ + do_intrinsic(_putLongRelease, jdk_internal_misc_Unsafe, putLongRelease_name, putLong_signature, F_R) \ + do_intrinsic(_putFloatRelease, jdk_internal_misc_Unsafe, putFloatRelease_name, putFloat_signature, F_R) \ + do_intrinsic(_putDoubleRelease, jdk_internal_misc_Unsafe, putDoubleRelease_name, putDouble_signature, F_R) \ + \ do_name(getShortUnaligned_name,"getShortUnaligned") do_name(putShortUnaligned_name,"putShortUnaligned") \ do_name(getCharUnaligned_name,"getCharUnaligned") do_name(putCharUnaligned_name,"putCharUnaligned") \ do_name(getIntUnaligned_name,"getIntUnaligned") do_name(putIntUnaligned_name,"putIntUnaligned") \ @@ -1197,24 +1255,68 @@ do_intrinsic(_putDouble_raw, jdk_internal_misc_Unsafe, putDouble_name, putDouble_raw_signature, F_R) \ do_intrinsic(_putAddress_raw, jdk_internal_misc_Unsafe, putAddress_name, putAddress_raw_signature, F_R) \ \ - do_intrinsic(_compareAndSwapObject, jdk_internal_misc_Unsafe, compareAndSwapObject_name, compareAndSwapObject_signature, F_R) \ - do_name( compareAndSwapObject_name, "compareAndSwapObject") \ - do_signature(compareAndSwapObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z") \ - do_intrinsic(_compareAndSwapLong, jdk_internal_misc_Unsafe, compareAndSwapLong_name, compareAndSwapLong_signature, F_R) \ - do_name( compareAndSwapLong_name, "compareAndSwapLong") \ - do_signature(compareAndSwapLong_signature, "(Ljava/lang/Object;JJJ)Z") \ - do_intrinsic(_compareAndSwapInt, jdk_internal_misc_Unsafe, compareAndSwapInt_name, compareAndSwapInt_signature, F_R) \ - do_name( compareAndSwapInt_name, "compareAndSwapInt") \ - do_signature(compareAndSwapInt_signature, "(Ljava/lang/Object;JII)Z") \ - do_intrinsic(_putOrderedObject, jdk_internal_misc_Unsafe, putOrderedObject_name, putOrderedObject_signature, F_R) \ - do_name( putOrderedObject_name, "putOrderedObject") \ - do_alias( putOrderedObject_signature, /*(LObject;JLObject;)V*/ putObject_signature) \ - do_intrinsic(_putOrderedLong, jdk_internal_misc_Unsafe, putOrderedLong_name, putOrderedLong_signature, F_R) \ - do_name( putOrderedLong_name, "putOrderedLong") \ - do_alias( putOrderedLong_signature, /*(Ljava/lang/Object;JJ)V*/ putLong_signature) \ - do_intrinsic(_putOrderedInt, jdk_internal_misc_Unsafe, putOrderedInt_name, putOrderedInt_signature, F_R) \ - do_name( putOrderedInt_name, "putOrderedInt") \ - do_alias( putOrderedInt_signature, /*(Ljava/lang/Object;JI)V*/ putInt_signature) \ + do_signature(compareAndSwapObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z") \ + do_signature(compareAndExchangeObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") \ + do_signature(compareAndSwapLong_signature, "(Ljava/lang/Object;JJJ)Z") \ + do_signature(compareAndExchangeLong_signature, "(Ljava/lang/Object;JJJ)J") \ + do_signature(compareAndSwapInt_signature, "(Ljava/lang/Object;JII)Z") \ + do_signature(compareAndExchangeInt_signature, "(Ljava/lang/Object;JII)I") \ + \ + do_name(compareAndSwapObject_name, "compareAndSwapObject") \ + do_name(compareAndExchangeObjectVolatile_name, "compareAndExchangeObjectVolatile") \ + do_name(compareAndExchangeObjectAcquire_name, "compareAndExchangeObjectAcquire") \ + do_name(compareAndExchangeObjectRelease_name, "compareAndExchangeObjectRelease") \ + do_name(compareAndSwapLong_name, "compareAndSwapLong") \ + do_name(compareAndExchangeLongVolatile_name, "compareAndExchangeLongVolatile") \ + do_name(compareAndExchangeLongAcquire_name, "compareAndExchangeLongAcquire") \ + do_name(compareAndExchangeLongRelease_name, "compareAndExchangeLongRelease") \ + do_name(compareAndSwapInt_name, "compareAndSwapInt") \ + do_name(compareAndExchangeIntVolatile_name, "compareAndExchangeIntVolatile") \ + do_name(compareAndExchangeIntAcquire_name, "compareAndExchangeIntAcquire") \ + do_name(compareAndExchangeIntRelease_name, "compareAndExchangeIntRelease") \ + \ + do_name(weakCompareAndSwapObject_name, "weakCompareAndSwapObject") \ + do_name(weakCompareAndSwapObjectAcquire_name, "weakCompareAndSwapObjectAcquire") \ + do_name(weakCompareAndSwapObjectRelease_name, "weakCompareAndSwapObjectRelease") \ + do_name(weakCompareAndSwapLong_name, "weakCompareAndSwapLong") \ + do_name(weakCompareAndSwapLongAcquire_name, "weakCompareAndSwapLongAcquire") \ + do_name(weakCompareAndSwapLongRelease_name, "weakCompareAndSwapLongRelease") \ + do_name(weakCompareAndSwapInt_name, "weakCompareAndSwapInt") \ + do_name(weakCompareAndSwapIntAcquire_name, "weakCompareAndSwapIntAcquire") \ + do_name(weakCompareAndSwapIntRelease_name, "weakCompareAndSwapIntRelease") \ + \ + do_intrinsic(_compareAndSwapObject, jdk_internal_misc_Unsafe, compareAndSwapObject_name, compareAndSwapObject_signature, F_RN) \ + do_intrinsic(_compareAndExchangeObjectVolatile, jdk_internal_misc_Unsafe, compareAndExchangeObjectVolatile_name, compareAndExchangeObject_signature, F_RN) \ + do_intrinsic(_compareAndExchangeObjectAcquire, jdk_internal_misc_Unsafe, compareAndExchangeObjectAcquire_name, compareAndExchangeObject_signature, F_R) \ + do_intrinsic(_compareAndExchangeObjectRelease, jdk_internal_misc_Unsafe, compareAndExchangeObjectRelease_name, compareAndExchangeObject_signature, F_R) \ + do_intrinsic(_compareAndSwapLong, jdk_internal_misc_Unsafe, compareAndSwapLong_name, compareAndSwapLong_signature, F_RN) \ + do_intrinsic(_compareAndExchangeLongVolatile, jdk_internal_misc_Unsafe, compareAndExchangeLongVolatile_name, compareAndExchangeLong_signature, F_RN) \ + do_intrinsic(_compareAndExchangeLongAcquire, jdk_internal_misc_Unsafe, compareAndExchangeLongAcquire_name, compareAndExchangeLong_signature, F_R) \ + do_intrinsic(_compareAndExchangeLongRelease, jdk_internal_misc_Unsafe, compareAndExchangeLongRelease_name, compareAndExchangeLong_signature, F_R) \ + do_intrinsic(_compareAndSwapInt, jdk_internal_misc_Unsafe, compareAndSwapInt_name, compareAndSwapInt_signature, F_RN) \ + do_intrinsic(_compareAndExchangeIntVolatile, jdk_internal_misc_Unsafe, compareAndExchangeIntVolatile_name, compareAndExchangeInt_signature, F_RN) \ + do_intrinsic(_compareAndExchangeIntAcquire, jdk_internal_misc_Unsafe, compareAndExchangeIntAcquire_name, compareAndExchangeInt_signature, F_R) \ + do_intrinsic(_compareAndExchangeIntRelease, jdk_internal_misc_Unsafe, compareAndExchangeIntRelease_name, compareAndExchangeInt_signature, F_R) \ + \ + do_intrinsic(_weakCompareAndSwapObject, jdk_internal_misc_Unsafe, weakCompareAndSwapObject_name, compareAndSwapObject_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapObjectAcquire, jdk_internal_misc_Unsafe, weakCompareAndSwapObjectAcquire_name, compareAndSwapObject_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapObjectRelease, jdk_internal_misc_Unsafe, weakCompareAndSwapObjectRelease_name, compareAndSwapObject_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapLong, jdk_internal_misc_Unsafe, weakCompareAndSwapLong_name, compareAndSwapLong_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapLongAcquire, jdk_internal_misc_Unsafe, weakCompareAndSwapLongAcquire_name, compareAndSwapLong_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapLongRelease, jdk_internal_misc_Unsafe, weakCompareAndSwapLongRelease_name, compareAndSwapLong_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapInt, jdk_internal_misc_Unsafe, weakCompareAndSwapInt_name, compareAndSwapInt_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapIntAcquire, jdk_internal_misc_Unsafe, weakCompareAndSwapIntAcquire_name, compareAndSwapInt_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapIntRelease, jdk_internal_misc_Unsafe, weakCompareAndSwapIntRelease_name, compareAndSwapInt_signature, F_R) \ + \ + do_intrinsic(_putOrderedObject, jdk_internal_misc_Unsafe, putOrderedObject_name, putOrderedObject_signature, F_RN) \ + do_name( putOrderedObject_name, "putOrderedObject") \ + do_alias( putOrderedObject_signature, /*(LObject;JLObject;)V*/ putObject_signature) \ + do_intrinsic(_putOrderedLong, jdk_internal_misc_Unsafe, putOrderedLong_name, putOrderedLong_signature, F_RN) \ + do_name( putOrderedLong_name, "putOrderedLong") \ + do_alias( putOrderedLong_signature, /*(Ljava/lang/Object;JJ)V*/ putLong_signature) \ + do_intrinsic(_putOrderedInt, jdk_internal_misc_Unsafe, putOrderedInt_name, putOrderedInt_signature, F_RN) \ + do_name( putOrderedInt_name, "putOrderedInt") \ + do_alias( putOrderedInt_signature, /*(Ljava/lang/Object;JI)V*/ putInt_signature) \ \ do_intrinsic(_getAndAddInt, jdk_internal_misc_Unsafe, getAndAddInt_name, getAndAddInt_signature, F_R) \ do_name( getAndAddInt_name, "getAndAddInt") \ diff --git a/hotspot/src/share/vm/opto/c2compiler.cpp b/hotspot/src/share/vm/opto/c2compiler.cpp index 7068b5cfb1a..aeea26748fe 100644 --- a/hotspot/src/share/vm/opto/c2compiler.cpp +++ b/hotspot/src/share/vm/opto/c2compiler.cpp @@ -243,14 +243,72 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_reverseBytes_l: if (!Matcher::match_rule_supported(Op_ReverseBytesL)) return false; break; + + /* CompareAndSwap, Object: */ case vmIntrinsics::_compareAndSwapObject: #ifdef _LP64 + if ( UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndSwapN)) return false; if (!UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndSwapP)) return false; +#else + if (!Matcher::match_rule_supported(Op_CompareAndSwapP)) return false; #endif break; + case vmIntrinsics::_weakCompareAndSwapObject: + case vmIntrinsics::_weakCompareAndSwapObjectAcquire: + case vmIntrinsics::_weakCompareAndSwapObjectRelease: +#ifdef _LP64 + if ( UseCompressedOops && !Matcher::match_rule_supported(Op_WeakCompareAndSwapN)) return false; + if (!UseCompressedOops && !Matcher::match_rule_supported(Op_WeakCompareAndSwapP)) return false; +#else + if (!Matcher::match_rule_supported(Op_WeakCompareAndSwapP)) return false; +#endif + break; + /* CompareAndSwap, Long: */ case vmIntrinsics::_compareAndSwapLong: if (!Matcher::match_rule_supported(Op_CompareAndSwapL)) return false; break; + case vmIntrinsics::_weakCompareAndSwapLong: + case vmIntrinsics::_weakCompareAndSwapLongAcquire: + case vmIntrinsics::_weakCompareAndSwapLongRelease: + if (!Matcher::match_rule_supported(Op_WeakCompareAndSwapL)) return false; + break; + + /* CompareAndSwap, Int: */ + case vmIntrinsics::_compareAndSwapInt: + if (!Matcher::match_rule_supported(Op_CompareAndSwapI)) return false; + break; + case vmIntrinsics::_weakCompareAndSwapInt: + case vmIntrinsics::_weakCompareAndSwapIntAcquire: + case vmIntrinsics::_weakCompareAndSwapIntRelease: + if (!Matcher::match_rule_supported(Op_WeakCompareAndSwapL)) return false; + break; + + /* CompareAndExchange, Object: */ + case vmIntrinsics::_compareAndExchangeObjectVolatile: + case vmIntrinsics::_compareAndExchangeObjectAcquire: + case vmIntrinsics::_compareAndExchangeObjectRelease: +#ifdef _LP64 + if ( UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndExchangeN)) return false; + if (!UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndExchangeP)) return false; +#else + if (!Matcher::match_rule_supported(Op_CompareAndExchangeP)) return false; +#endif + break; + + /* CompareAndExchange, Long: */ + case vmIntrinsics::_compareAndExchangeLongVolatile: + case vmIntrinsics::_compareAndExchangeLongAcquire: + case vmIntrinsics::_compareAndExchangeLongRelease: + if (!Matcher::match_rule_supported(Op_CompareAndExchangeL)) return false; + break; + + /* CompareAndExchange, Int: */ + case vmIntrinsics::_compareAndExchangeIntVolatile: + case vmIntrinsics::_compareAndExchangeIntAcquire: + case vmIntrinsics::_compareAndExchangeIntRelease: + if (!Matcher::match_rule_supported(Op_CompareAndExchangeI)) return false; + break; + case vmIntrinsics::_getAndAddInt: if (!Matcher::match_rule_supported(Op_GetAndAddI)) return false; break; @@ -382,6 +440,42 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_putLongVolatile: case vmIntrinsics::_putFloatVolatile: case vmIntrinsics::_putDoubleVolatile: + case vmIntrinsics::_getObjectAcquire: + case vmIntrinsics::_getBooleanAcquire: + case vmIntrinsics::_getByteAcquire: + case vmIntrinsics::_getShortAcquire: + case vmIntrinsics::_getCharAcquire: + case vmIntrinsics::_getIntAcquire: + case vmIntrinsics::_getLongAcquire: + case vmIntrinsics::_getFloatAcquire: + case vmIntrinsics::_getDoubleAcquire: + case vmIntrinsics::_putObjectRelease: + case vmIntrinsics::_putBooleanRelease: + case vmIntrinsics::_putByteRelease: + case vmIntrinsics::_putShortRelease: + case vmIntrinsics::_putCharRelease: + case vmIntrinsics::_putIntRelease: + case vmIntrinsics::_putLongRelease: + case vmIntrinsics::_putFloatRelease: + case vmIntrinsics::_putDoubleRelease: + case vmIntrinsics::_getObjectOpaque: + case vmIntrinsics::_getBooleanOpaque: + case vmIntrinsics::_getByteOpaque: + case vmIntrinsics::_getShortOpaque: + case vmIntrinsics::_getCharOpaque: + case vmIntrinsics::_getIntOpaque: + case vmIntrinsics::_getLongOpaque: + case vmIntrinsics::_getFloatOpaque: + case vmIntrinsics::_getDoubleOpaque: + case vmIntrinsics::_putObjectOpaque: + case vmIntrinsics::_putBooleanOpaque: + case vmIntrinsics::_putByteOpaque: + case vmIntrinsics::_putShortOpaque: + case vmIntrinsics::_putCharOpaque: + case vmIntrinsics::_putIntOpaque: + case vmIntrinsics::_putLongOpaque: + case vmIntrinsics::_putFloatOpaque: + case vmIntrinsics::_putDoubleOpaque: case vmIntrinsics::_getShortUnaligned: case vmIntrinsics::_getCharUnaligned: case vmIntrinsics::_getIntUnaligned: @@ -390,7 +484,6 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_putCharUnaligned: case vmIntrinsics::_putIntUnaligned: case vmIntrinsics::_putLongUnaligned: - case vmIntrinsics::_compareAndSwapInt: case vmIntrinsics::_putOrderedObject: case vmIntrinsics::_putOrderedInt: case vmIntrinsics::_putOrderedLong: diff --git a/hotspot/src/share/vm/opto/classes.hpp b/hotspot/src/share/vm/opto/classes.hpp index e101a9768a2..ee36282de38 100644 --- a/hotspot/src/share/vm/opto/classes.hpp +++ b/hotspot/src/share/vm/opto/classes.hpp @@ -85,6 +85,14 @@ macro(CompareAndSwapI) macro(CompareAndSwapL) macro(CompareAndSwapP) macro(CompareAndSwapN) +macro(WeakCompareAndSwapI) +macro(WeakCompareAndSwapL) +macro(WeakCompareAndSwapP) +macro(WeakCompareAndSwapN) +macro(CompareAndExchangeI) +macro(CompareAndExchangeL) +macro(CompareAndExchangeP) +macro(CompareAndExchangeN) macro(GetAndAddI) macro(GetAndAddL) macro(GetAndSetI) diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index 6e3e46d790f..ec737694e53 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -2786,6 +2786,14 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { case Op_CompareAndSwapL: case Op_CompareAndSwapP: case Op_CompareAndSwapN: + case Op_WeakCompareAndSwapI: + case Op_WeakCompareAndSwapL: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: + case Op_CompareAndExchangeI: + case Op_CompareAndExchangeL: + case Op_CompareAndExchangeP: + case Op_CompareAndExchangeN: case Op_GetAndAddI: case Op_GetAndAddL: case Op_GetAndSetI: diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index 310ac7fa70e..d2641d2acca 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -490,6 +490,8 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de } break; } + case Op_CompareAndExchangeP: + case Op_CompareAndExchangeN: case Op_GetAndSetP: case Op_GetAndSetN: { add_objload_to_connection_graph(n, delayed_worklist); @@ -499,6 +501,8 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de case Op_StoreN: case Op_StoreNKlass: case Op_StorePConditional: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: case Op_CompareAndSwapP: case Op_CompareAndSwapN: { Node* adr = n->in(MemNode::Address); @@ -698,8 +702,12 @@ void ConnectionGraph::add_final_edges(Node *n) { case Op_StoreN: case Op_StoreNKlass: case Op_StorePConditional: + case Op_CompareAndExchangeP: + case Op_CompareAndExchangeN: case Op_CompareAndSwapP: case Op_CompareAndSwapN: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: case Op_GetAndSetP: case Op_GetAndSetN: { Node* adr = n->in(MemNode::Address); diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index f604d59a1ac..de751bc1a97 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -241,7 +241,9 @@ class LibraryCallKit : public GraphKit { // Generates the guards that check whether the result of // Unsafe.getObject should be recorded in an SATB log buffer. void insert_pre_barrier(Node* base_oop, Node* offset, Node* pre_val, bool need_mem_bar); - bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool is_unaligned); + + typedef enum { Relaxed, Opaque, Volatile, Acquire, Release } AccessKind; + bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, AccessKind kind, bool is_unaligned); static bool klass_needs_init_guard(Node* kls); bool inline_unsafe_allocate(); bool inline_unsafe_copyMemory(); @@ -274,9 +276,10 @@ class LibraryCallKit : public GraphKit { JVMState* arraycopy_restore_alloc_state(AllocateArrayNode* alloc, int& saved_reexecute_sp); void arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms, int saved_reexecute_sp); - typedef enum { LS_xadd, LS_xchg, LS_cmpxchg } LoadStoreKind; - bool inline_unsafe_load_store(BasicType type, LoadStoreKind kind); - bool inline_unsafe_ordered_store(BasicType type); + typedef enum { LS_get_add, LS_get_set, LS_cmp_swap, LS_cmp_swap_weak, LS_cmp_exchange } LoadStoreKind; + MemNode::MemOrd access_kind_to_memord_LS(AccessKind access_kind, bool is_store); + MemNode::MemOrd access_kind_to_memord(AccessKind access_kind); + bool inline_unsafe_load_store(BasicType type, LoadStoreKind kind, AccessKind access_kind); bool inline_unsafe_fence(vmIntrinsics::ID id); bool inline_fp_conversions(vmIntrinsics::ID id); bool inline_number_methods(vmIntrinsics::ID id); @@ -553,86 +556,147 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_inflateStringC: case vmIntrinsics::_inflateStringB: return inline_string_copy(!is_compress); - case vmIntrinsics::_getObject: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, !is_volatile, false); - case vmIntrinsics::_getBoolean: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, !is_volatile, false); - case vmIntrinsics::_getByte: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, !is_volatile, false); - case vmIntrinsics::_getShort: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile, false); - case vmIntrinsics::_getChar: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile, false); - case vmIntrinsics::_getInt: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile, false); - case vmIntrinsics::_getLong: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile, false); - case vmIntrinsics::_getFloat: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, !is_volatile, false); - case vmIntrinsics::_getDouble: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, !is_volatile, false); - case vmIntrinsics::_putObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, !is_volatile, false); - case vmIntrinsics::_putBoolean: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, !is_volatile, false); - case vmIntrinsics::_putByte: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, !is_volatile, false); - case vmIntrinsics::_putShort: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile, false); - case vmIntrinsics::_putChar: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile, false); - case vmIntrinsics::_putInt: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile, false); - case vmIntrinsics::_putLong: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile, false); - case vmIntrinsics::_putFloat: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, !is_volatile, false); - case vmIntrinsics::_putDouble: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, !is_volatile, false); + case vmIntrinsics::_getObject: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, Relaxed, false); + case vmIntrinsics::_getBoolean: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, Relaxed, false); + case vmIntrinsics::_getByte: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, Relaxed, false); + case vmIntrinsics::_getShort: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Relaxed, false); + case vmIntrinsics::_getChar: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Relaxed, false); + case vmIntrinsics::_getInt: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Relaxed, false); + case vmIntrinsics::_getLong: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Relaxed, false); + case vmIntrinsics::_getFloat: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, Relaxed, false); + case vmIntrinsics::_getDouble: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, Relaxed, false); - case vmIntrinsics::_getByte_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_BYTE, !is_volatile, false); - case vmIntrinsics::_getShort_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_SHORT, !is_volatile, false); - case vmIntrinsics::_getChar_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_CHAR, !is_volatile, false); - case vmIntrinsics::_getInt_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_INT, !is_volatile, false); - case vmIntrinsics::_getLong_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_LONG, !is_volatile, false); - case vmIntrinsics::_getFloat_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_FLOAT, !is_volatile, false); - case vmIntrinsics::_getDouble_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_DOUBLE, !is_volatile, false); - case vmIntrinsics::_getAddress_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_ADDRESS, !is_volatile, false); + case vmIntrinsics::_putObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Relaxed, false); + case vmIntrinsics::_putBoolean: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, Relaxed, false); + case vmIntrinsics::_putByte: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, Relaxed, false); + case vmIntrinsics::_putShort: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Relaxed, false); + case vmIntrinsics::_putChar: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Relaxed, false); + case vmIntrinsics::_putInt: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Relaxed, false); + case vmIntrinsics::_putLong: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Relaxed, false); + case vmIntrinsics::_putFloat: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, Relaxed, false); + case vmIntrinsics::_putDouble: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, Relaxed, false); - case vmIntrinsics::_putByte_raw: return inline_unsafe_access( is_native_ptr, is_store, T_BYTE, !is_volatile, false); - case vmIntrinsics::_putShort_raw: return inline_unsafe_access( is_native_ptr, is_store, T_SHORT, !is_volatile, false); - case vmIntrinsics::_putChar_raw: return inline_unsafe_access( is_native_ptr, is_store, T_CHAR, !is_volatile, false); - case vmIntrinsics::_putInt_raw: return inline_unsafe_access( is_native_ptr, is_store, T_INT, !is_volatile, false); - case vmIntrinsics::_putLong_raw: return inline_unsafe_access( is_native_ptr, is_store, T_LONG, !is_volatile, false); - case vmIntrinsics::_putFloat_raw: return inline_unsafe_access( is_native_ptr, is_store, T_FLOAT, !is_volatile, false); - case vmIntrinsics::_putDouble_raw: return inline_unsafe_access( is_native_ptr, is_store, T_DOUBLE, !is_volatile, false); - case vmIntrinsics::_putAddress_raw: return inline_unsafe_access( is_native_ptr, is_store, T_ADDRESS, !is_volatile, false); + case vmIntrinsics::_getByte_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_BYTE, Relaxed, false); + case vmIntrinsics::_getShort_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_SHORT, Relaxed, false); + case vmIntrinsics::_getChar_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_CHAR, Relaxed, false); + case vmIntrinsics::_getInt_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_INT, Relaxed, false); + case vmIntrinsics::_getLong_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_LONG, Relaxed, false); + case vmIntrinsics::_getFloat_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_FLOAT, Relaxed, false); + case vmIntrinsics::_getDouble_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_DOUBLE, Relaxed, false); + case vmIntrinsics::_getAddress_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_ADDRESS, Relaxed, false); - case vmIntrinsics::_getObjectVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, is_volatile, false); - case vmIntrinsics::_getBooleanVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, is_volatile, false); - case vmIntrinsics::_getByteVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, is_volatile, false); - case vmIntrinsics::_getShortVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, is_volatile, false); - case vmIntrinsics::_getCharVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, is_volatile, false); - case vmIntrinsics::_getIntVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, is_volatile, false); - case vmIntrinsics::_getLongVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, is_volatile, false); - case vmIntrinsics::_getFloatVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, is_volatile, false); - case vmIntrinsics::_getDoubleVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, is_volatile, false); + case vmIntrinsics::_putByte_raw: return inline_unsafe_access( is_native_ptr, is_store, T_BYTE, Relaxed, false); + case vmIntrinsics::_putShort_raw: return inline_unsafe_access( is_native_ptr, is_store, T_SHORT, Relaxed, false); + case vmIntrinsics::_putChar_raw: return inline_unsafe_access( is_native_ptr, is_store, T_CHAR, Relaxed, false); + case vmIntrinsics::_putInt_raw: return inline_unsafe_access( is_native_ptr, is_store, T_INT, Relaxed, false); + case vmIntrinsics::_putLong_raw: return inline_unsafe_access( is_native_ptr, is_store, T_LONG, Relaxed, false); + case vmIntrinsics::_putFloat_raw: return inline_unsafe_access( is_native_ptr, is_store, T_FLOAT, Relaxed, false); + case vmIntrinsics::_putDouble_raw: return inline_unsafe_access( is_native_ptr, is_store, T_DOUBLE, Relaxed, false); + case vmIntrinsics::_putAddress_raw: return inline_unsafe_access( is_native_ptr, is_store, T_ADDRESS, Relaxed, false); - case vmIntrinsics::_putObjectVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, is_volatile, false); - case vmIntrinsics::_putBooleanVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, is_volatile, false); - case vmIntrinsics::_putByteVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, is_volatile, false); - case vmIntrinsics::_putShortVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, is_volatile, false); - case vmIntrinsics::_putCharVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, is_volatile, false); - case vmIntrinsics::_putIntVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, is_volatile, false); - case vmIntrinsics::_putLongVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, is_volatile, false); - case vmIntrinsics::_putFloatVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, is_volatile, false); - case vmIntrinsics::_putDoubleVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, is_volatile, false); + case vmIntrinsics::_getObjectVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, Volatile, false); + case vmIntrinsics::_getBooleanVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, Volatile, false); + case vmIntrinsics::_getByteVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, Volatile, false); + case vmIntrinsics::_getShortVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Volatile, false); + case vmIntrinsics::_getCharVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Volatile, false); + case vmIntrinsics::_getIntVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Volatile, false); + case vmIntrinsics::_getLongVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Volatile, false); + case vmIntrinsics::_getFloatVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, Volatile, false); + case vmIntrinsics::_getDoubleVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, Volatile, false); - case vmIntrinsics::_getShortUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile, true); - case vmIntrinsics::_getCharUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile, true); - case vmIntrinsics::_getIntUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile, true); - case vmIntrinsics::_getLongUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile, true); + case vmIntrinsics::_putObjectVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Volatile, false); + case vmIntrinsics::_putBooleanVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, Volatile, false); + case vmIntrinsics::_putByteVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, Volatile, false); + case vmIntrinsics::_putShortVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Volatile, false); + case vmIntrinsics::_putCharVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Volatile, false); + case vmIntrinsics::_putIntVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Volatile, false); + case vmIntrinsics::_putLongVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Volatile, false); + case vmIntrinsics::_putFloatVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, Volatile, false); + case vmIntrinsics::_putDoubleVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, Volatile, false); - case vmIntrinsics::_putShortUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile, true); - case vmIntrinsics::_putCharUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile, true); - case vmIntrinsics::_putIntUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile, true); - case vmIntrinsics::_putLongUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile, true); + case vmIntrinsics::_getShortUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Relaxed, true); + case vmIntrinsics::_getCharUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Relaxed, true); + case vmIntrinsics::_getIntUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Relaxed, true); + case vmIntrinsics::_getLongUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Relaxed, true); - case vmIntrinsics::_compareAndSwapObject: return inline_unsafe_load_store(T_OBJECT, LS_cmpxchg); - case vmIntrinsics::_compareAndSwapInt: return inline_unsafe_load_store(T_INT, LS_cmpxchg); - case vmIntrinsics::_compareAndSwapLong: return inline_unsafe_load_store(T_LONG, LS_cmpxchg); + case vmIntrinsics::_putShortUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Relaxed, true); + case vmIntrinsics::_putCharUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Relaxed, true); + case vmIntrinsics::_putIntUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Relaxed, true); + case vmIntrinsics::_putLongUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Relaxed, true); - case vmIntrinsics::_putOrderedObject: return inline_unsafe_ordered_store(T_OBJECT); - case vmIntrinsics::_putOrderedInt: return inline_unsafe_ordered_store(T_INT); - case vmIntrinsics::_putOrderedLong: return inline_unsafe_ordered_store(T_LONG); + case vmIntrinsics::_putOrderedObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Release, false); + case vmIntrinsics::_putOrderedInt: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Release, false); + case vmIntrinsics::_putOrderedLong: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Release, false); - case vmIntrinsics::_getAndAddInt: return inline_unsafe_load_store(T_INT, LS_xadd); - case vmIntrinsics::_getAndAddLong: return inline_unsafe_load_store(T_LONG, LS_xadd); - case vmIntrinsics::_getAndSetInt: return inline_unsafe_load_store(T_INT, LS_xchg); - case vmIntrinsics::_getAndSetLong: return inline_unsafe_load_store(T_LONG, LS_xchg); - case vmIntrinsics::_getAndSetObject: return inline_unsafe_load_store(T_OBJECT, LS_xchg); + case vmIntrinsics::_getObjectAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, Acquire, false); + case vmIntrinsics::_getBooleanAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, Acquire, false); + case vmIntrinsics::_getByteAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, Acquire, false); + case vmIntrinsics::_getShortAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Acquire, false); + case vmIntrinsics::_getCharAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Acquire, false); + case vmIntrinsics::_getIntAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Acquire, false); + case vmIntrinsics::_getLongAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Acquire, false); + case vmIntrinsics::_getFloatAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, Acquire, false); + case vmIntrinsics::_getDoubleAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, Acquire, false); + + case vmIntrinsics::_putObjectRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Release, false); + case vmIntrinsics::_putBooleanRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, Release, false); + case vmIntrinsics::_putByteRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, Release, false); + case vmIntrinsics::_putShortRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Release, false); + case vmIntrinsics::_putCharRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Release, false); + case vmIntrinsics::_putIntRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Release, false); + case vmIntrinsics::_putLongRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Release, false); + case vmIntrinsics::_putFloatRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, Release, false); + case vmIntrinsics::_putDoubleRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, Release, false); + + case vmIntrinsics::_getObjectOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, Opaque, false); + case vmIntrinsics::_getBooleanOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, Opaque, false); + case vmIntrinsics::_getByteOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, Opaque, false); + case vmIntrinsics::_getShortOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Opaque, false); + case vmIntrinsics::_getCharOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Opaque, false); + case vmIntrinsics::_getIntOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Opaque, false); + case vmIntrinsics::_getLongOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Opaque, false); + case vmIntrinsics::_getFloatOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, Opaque, false); + case vmIntrinsics::_getDoubleOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, Opaque, false); + + case vmIntrinsics::_putObjectOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Opaque, false); + case vmIntrinsics::_putBooleanOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, Opaque, false); + case vmIntrinsics::_putByteOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, Opaque, false); + case vmIntrinsics::_putShortOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Opaque, false); + case vmIntrinsics::_putCharOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Opaque, false); + case vmIntrinsics::_putIntOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Opaque, false); + case vmIntrinsics::_putLongOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Opaque, false); + case vmIntrinsics::_putFloatOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, Opaque, false); + case vmIntrinsics::_putDoubleOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, Opaque, false); + + case vmIntrinsics::_compareAndSwapObject: return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap, Volatile); + case vmIntrinsics::_compareAndSwapInt: return inline_unsafe_load_store(T_INT, LS_cmp_swap, Volatile); + case vmIntrinsics::_compareAndSwapLong: return inline_unsafe_load_store(T_LONG, LS_cmp_swap, Volatile); + + case vmIntrinsics::_weakCompareAndSwapObject: return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap_weak, Relaxed); + case vmIntrinsics::_weakCompareAndSwapObjectAcquire: return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap_weak, Acquire); + case vmIntrinsics::_weakCompareAndSwapObjectRelease: return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap_weak, Release); + case vmIntrinsics::_weakCompareAndSwapInt: return inline_unsafe_load_store(T_INT, LS_cmp_swap_weak, Relaxed); + case vmIntrinsics::_weakCompareAndSwapIntAcquire: return inline_unsafe_load_store(T_INT, LS_cmp_swap_weak, Acquire); + case vmIntrinsics::_weakCompareAndSwapIntRelease: return inline_unsafe_load_store(T_INT, LS_cmp_swap_weak, Release); + case vmIntrinsics::_weakCompareAndSwapLong: return inline_unsafe_load_store(T_LONG, LS_cmp_swap_weak, Relaxed); + case vmIntrinsics::_weakCompareAndSwapLongAcquire: return inline_unsafe_load_store(T_LONG, LS_cmp_swap_weak, Acquire); + case vmIntrinsics::_weakCompareAndSwapLongRelease: return inline_unsafe_load_store(T_LONG, LS_cmp_swap_weak, Release); + + case vmIntrinsics::_compareAndExchangeObjectVolatile: return inline_unsafe_load_store(T_OBJECT, LS_cmp_exchange, Volatile); + case vmIntrinsics::_compareAndExchangeObjectAcquire: return inline_unsafe_load_store(T_OBJECT, LS_cmp_exchange, Acquire); + case vmIntrinsics::_compareAndExchangeObjectRelease: return inline_unsafe_load_store(T_OBJECT, LS_cmp_exchange, Release); + case vmIntrinsics::_compareAndExchangeIntVolatile: return inline_unsafe_load_store(T_INT, LS_cmp_exchange, Volatile); + case vmIntrinsics::_compareAndExchangeIntAcquire: return inline_unsafe_load_store(T_INT, LS_cmp_exchange, Acquire); + case vmIntrinsics::_compareAndExchangeIntRelease: return inline_unsafe_load_store(T_INT, LS_cmp_exchange, Release); + case vmIntrinsics::_compareAndExchangeLongVolatile: return inline_unsafe_load_store(T_LONG, LS_cmp_exchange, Volatile); + case vmIntrinsics::_compareAndExchangeLongAcquire: return inline_unsafe_load_store(T_LONG, LS_cmp_exchange, Acquire); + case vmIntrinsics::_compareAndExchangeLongRelease: return inline_unsafe_load_store(T_LONG, LS_cmp_exchange, Release); + + case vmIntrinsics::_getAndAddInt: return inline_unsafe_load_store(T_INT, LS_get_add, Volatile); + case vmIntrinsics::_getAndAddLong: return inline_unsafe_load_store(T_LONG, LS_get_add, Volatile); + case vmIntrinsics::_getAndSetInt: return inline_unsafe_load_store(T_INT, LS_get_set, Volatile); + case vmIntrinsics::_getAndSetLong: return inline_unsafe_load_store(T_LONG, LS_get_set, Volatile); + case vmIntrinsics::_getAndSetObject: return inline_unsafe_load_store(T_OBJECT, LS_get_set, Volatile); case vmIntrinsics::_loadFence: case vmIntrinsics::_storeFence: @@ -2284,8 +2348,10 @@ const TypeOopPtr* LibraryCallKit::sharpen_unsafe_type(Compile::AliasType* alias_ return NULL; } -bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool unaligned) { +bool LibraryCallKit::inline_unsafe_access(const bool is_native_ptr, bool is_store, const BasicType type, const AccessKind kind, const bool unaligned) { if (callee()->is_static()) return false; // caller must have the capability! + guarantee(!is_store || kind != Acquire, "Acquire accesses can be produced only for loads"); + guarantee( is_store || kind != Release, "Release accesses can be produced only for stores"); #ifndef PRODUCT { @@ -2374,7 +2440,42 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas // the barriers get omitted and the unsafe reference begins to "pollute" // the alias analysis of the rest of the graph, either Compile::can_alias // or Compile::must_alias will throw a diagnostic assert.) - bool need_mem_bar = (alias_type->adr_type() == TypeOopPtr::BOTTOM); + bool need_mem_bar; + switch (kind) { + case Relaxed: + need_mem_bar = (alias_type->adr_type() == TypeOopPtr::BOTTOM); + break; + case Opaque: + // Opaque uses CPUOrder membars for protection against code movement. + case Acquire: + case Release: + case Volatile: + need_mem_bar = true; + break; + default: + ShouldNotReachHere(); + } + + // Some accesses require access atomicity for all types, notably longs and doubles. + // When AlwaysAtomicAccesses is enabled, all accesses are atomic. + bool requires_atomic_access = false; + switch (kind) { + case Relaxed: + case Opaque: + requires_atomic_access = AlwaysAtomicAccesses; + break; + case Acquire: + case Release: + case Volatile: + requires_atomic_access = true; + break; + default: + ShouldNotReachHere(); + } + + // Figure out the memory ordering. + // Acquire/Release/Volatile accesses require marking the loads/stores with MemOrd + MemNode::MemOrd mo = access_kind_to_memord_LS(kind, is_store); // If we are reading the value of the referent field of a Reference // object (either by using Unsafe directly or through reflection) @@ -2401,22 +2502,30 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas // and it is not possible to fully distinguish unintended nulls // from intended ones in this API. - if (is_volatile) { - // We need to emit leading and trailing CPU membars (see below) in - // addition to memory membars when is_volatile. This is a little - // too strong, but avoids the need to insert per-alias-type - // volatile membars (for stores; compare Parse::do_put_xxx), which - // we cannot do effectively here because we probably only have a - // rough approximation of type. - need_mem_bar = true; - // For Stores, place a memory ordering barrier now. - if (is_store) { - insert_mem_bar(Op_MemBarRelease); - } else { - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - insert_mem_bar(Op_MemBarVolatile); + // We need to emit leading and trailing CPU membars (see below) in + // addition to memory membars for special access modes. This is a little + // too strong, but avoids the need to insert per-alias-type + // volatile membars (for stores; compare Parse::do_put_xxx), which + // we cannot do effectively here because we probably only have a + // rough approximation of type. + + switch(kind) { + case Relaxed: + case Opaque: + case Acquire: + break; + case Release: + case Volatile: + if (is_store) { + insert_mem_bar(Op_MemBarRelease); + } else { + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + insert_mem_bar(Op_MemBarVolatile); + } } - } + break; + default: + ShouldNotReachHere(); } // Memory barrier to prevent normal and 'unsafe' accesses from @@ -2460,10 +2569,9 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas } } if (p == NULL) { - MemNode::MemOrd mo = is_volatile ? MemNode::acquire : MemNode::unordered; // To be valid, unsafe loads may depend on other conditions than // the one that guards them: pin the Load node - p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, is_volatile, unaligned, mismatched); + p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, requires_atomic_access, unaligned, mismatched); // load value switch (type) { case T_BOOLEAN: @@ -2477,7 +2585,9 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas break; case T_OBJECT: if (need_read_barrier) { - insert_pre_barrier(heap_base_oop, offset, p, !(is_volatile || need_mem_bar)); + // We do not require a mem bar inside pre_barrier if need_mem_bar + // is set: the barriers would be emitted by us. + insert_pre_barrier(heap_base_oop, offset, p, !need_mem_bar); } break; case T_ADDRESS: @@ -2508,9 +2618,8 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas break; } - MemNode::MemOrd mo = is_volatile ? MemNode::release : MemNode::unordered; - if (type != T_OBJECT ) { - (void) store_to_memory(control(), adr, val, type, adr_type, mo, is_volatile, unaligned, mismatched); + if (type != T_OBJECT) { + (void) store_to_memory(control(), adr, val, type, adr_type, mo, requires_atomic_access, unaligned, mismatched); } else { // Possibly an oop being stored to Java heap or native memory if (!TypePtr::NULL_PTR->higher_equal(_gvn.type(heap_base_oop))) { @@ -2531,7 +2640,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas // Update IdealKit memory. __ sync_kit(this); } __ else_(); { - __ store(__ ctrl(), adr, val, type, alias_type->index(), mo, is_volatile, mismatched); + __ store(__ ctrl(), adr, val, type, alias_type->index(), mo, requires_atomic_access, mismatched); } __ end_if(); // Final sync IdealKit and GraphKit. final_sync(ideal); @@ -2540,14 +2649,23 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas } } - if (is_volatile) { - if (!is_store) { - insert_mem_bar(Op_MemBarAcquire); - } else { - if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { - insert_mem_bar(Op_MemBarVolatile); + switch(kind) { + case Relaxed: + case Opaque: + case Release: + break; + case Acquire: + case Volatile: + if (!is_store) { + insert_mem_bar(Op_MemBarAcquire); + } else { + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + insert_mem_bar(Op_MemBarVolatile); + } } - } + break; + default: + ShouldNotReachHere(); } if (need_mem_bar) insert_mem_bar(Op_MemBarCPUOrder); @@ -2558,21 +2676,52 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas //----------------------------inline_unsafe_load_store---------------------------- // This method serves a couple of different customers (depending on LoadStoreKind): // -// LS_cmpxchg: -// public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); -// public final native boolean compareAndSwapInt( Object o, long offset, int expected, int x); -// public final native boolean compareAndSwapLong( Object o, long offset, long expected, long x); +// LS_cmp_swap: // -// LS_xadd: -// public int getAndAddInt( Object o, long offset, int delta) -// public long getAndAddLong(Object o, long offset, long delta) +// boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); +// boolean compareAndSwapInt( Object o, long offset, int expected, int x); +// boolean compareAndSwapLong( Object o, long offset, long expected, long x); +// +// LS_cmp_swap_weak: +// +// boolean weakCompareAndSwapObject( Object o, long offset, Object expected, Object x); +// boolean weakCompareAndSwapObjectAcquire(Object o, long offset, Object expected, Object x); +// boolean weakCompareAndSwapObjectRelease(Object o, long offset, Object expected, Object x); +// +// boolean weakCompareAndSwapInt( Object o, long offset, int expected, int x); +// boolean weakCompareAndSwapIntAcquire( Object o, long offset, int expected, int x); +// boolean weakCompareAndSwapIntRelease( Object o, long offset, int expected, int x); +// +// boolean weakCompareAndSwapLong( Object o, long offset, long expected, long x); +// boolean weakCompareAndSwapLongAcquire( Object o, long offset, long expected, long x); +// boolean weakCompareAndSwapLongRelease( Object o, long offset, long expected, long x); +// +// LS_cmp_exchange: +// +// Object compareAndExchangeObjectVolatile(Object o, long offset, Object expected, Object x); +// Object compareAndExchangeObjectAcquire( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeObjectRelease( Object o, long offset, Object expected, Object x); +// +// Object compareAndExchangeIntVolatile( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeIntAcquire( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeIntRelease( Object o, long offset, Object expected, Object x); +// +// Object compareAndExchangeLongVolatile( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeLongAcquire( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeLongRelease( Object o, long offset, Object expected, Object x); +// +// LS_get_add: +// +// int getAndAddInt( Object o, long offset, int delta) +// long getAndAddLong(Object o, long offset, long delta) +// +// LS_get_set: // -// LS_xchg: // int getAndSet(Object o, long offset, int newValue) // long getAndSet(Object o, long offset, long newValue) // Object getAndSet(Object o, long offset, Object newValue) // -bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind) { +bool LibraryCallKit::inline_unsafe_load_store(const BasicType type, const LoadStoreKind kind, const AccessKind access_kind) { // This basic scheme here is the same as inline_unsafe_access, but // differs in enough details that combining them would make the code // overly confusing. (This is a true fact! I originally combined @@ -2589,7 +2738,9 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind // Check the signatures. ciSignature* sig = callee()->signature(); rtype = sig->return_type()->basic_type(); - if (kind == LS_xadd || kind == LS_xchg) { + switch(kind) { + case LS_get_add: + case LS_get_set: { // Check the signatures. #ifdef ASSERT assert(rtype == type, "get and set must return the expected type"); @@ -2598,7 +2749,10 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind assert(sig->type_at(1)->basic_type() == T_LONG, "get and set offset is long"); assert(sig->type_at(2)->basic_type() == type, "get and set must take expected type as new value/delta"); #endif // ASSERT - } else if (kind == LS_cmpxchg) { + break; + } + case LS_cmp_swap: + case LS_cmp_swap_weak: { // Check the signatures. #ifdef ASSERT assert(rtype == T_BOOLEAN, "CAS must return boolean"); @@ -2606,8 +2760,20 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind assert(sig->type_at(0)->basic_type() == T_OBJECT, "CAS base is object"); assert(sig->type_at(1)->basic_type() == T_LONG, "CAS offset is long"); #endif // ASSERT - } else { - ShouldNotReachHere(); + break; + } + case LS_cmp_exchange: { + // Check the signatures. +#ifdef ASSERT + assert(rtype == type, "CAS must return the expected type"); + assert(sig->count() == 4, "CAS has 4 arguments"); + assert(sig->type_at(0)->basic_type() == T_OBJECT, "CAS base is object"); + assert(sig->type_at(1)->basic_type() == T_LONG, "CAS offset is long"); +#endif // ASSERT + break; + } + default: + ShouldNotReachHere(); } } #endif //PRODUCT @@ -2620,19 +2786,29 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind Node* offset = NULL; Node* oldval = NULL; Node* newval = NULL; - if (kind == LS_cmpxchg) { - const bool two_slot_type = type2size[type] == 2; - receiver = argument(0); // type: oop - base = argument(1); // type: oop - offset = argument(2); // type: long - oldval = argument(4); // type: oop, int, or long - newval = argument(two_slot_type ? 6 : 5); // type: oop, int, or long - } else if (kind == LS_xadd || kind == LS_xchg){ - receiver = argument(0); // type: oop - base = argument(1); // type: oop - offset = argument(2); // type: long - oldval = NULL; - newval = argument(4); // type: oop, int, or long + switch(kind) { + case LS_cmp_swap: + case LS_cmp_swap_weak: + case LS_cmp_exchange: { + const bool two_slot_type = type2size[type] == 2; + receiver = argument(0); // type: oop + base = argument(1); // type: oop + offset = argument(2); // type: long + oldval = argument(4); // type: oop, int, or long + newval = argument(two_slot_type ? 6 : 5); // type: oop, int, or long + break; + } + case LS_get_add: + case LS_get_set: { + receiver = argument(0); // type: oop + base = argument(1); // type: oop + offset = argument(2); // type: long + oldval = NULL; + newval = argument(4); // type: oop, int, or long + break; + } + default: + ShouldNotReachHere(); } // Null check receiver. @@ -2657,11 +2833,23 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind Compile::AliasType* alias_type = C->alias_type(adr_type); assert(alias_type->index() != Compile::AliasIdxBot, "no bare pointers here"); - if (kind == LS_xchg && type == T_OBJECT) { - const TypeOopPtr* tjp = sharpen_unsafe_type(alias_type, adr_type); - if (tjp != NULL) { - value_type = tjp; + switch (kind) { + case LS_get_set: + case LS_cmp_exchange: { + if (type == T_OBJECT) { + const TypeOopPtr* tjp = sharpen_unsafe_type(alias_type, adr_type); + if (tjp != NULL) { + value_type = tjp; + } + } + break; } + case LS_cmp_swap: + case LS_cmp_swap_weak: + case LS_get_add: + break; + default: + ShouldNotReachHere(); } int alias_idx = C->get_alias_index(adr_type); @@ -2671,9 +2859,22 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind // into actual barriers on most machines, but we still need rest of // compiler to respect ordering. - insert_mem_bar(Op_MemBarRelease); + switch (access_kind) { + case Relaxed: + case Acquire: + break; + case Release: + case Volatile: + insert_mem_bar(Op_MemBarRelease); + break; + default: + ShouldNotReachHere(); + } insert_mem_bar(Op_MemBarCPUOrder); + // Figure out the memory ordering. + MemNode::MemOrd mo = access_kind_to_memord(access_kind); + // 4984716: MemBars must be inserted before this // memory node in order to avoid a false // dependency which will confuse the scheduler. @@ -2684,25 +2885,45 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind Node* load_store = NULL; switch(type) { case T_INT: - if (kind == LS_xadd) { - load_store = _gvn.transform(new GetAndAddINode(control(), mem, adr, newval, adr_type)); - } else if (kind == LS_xchg) { - load_store = _gvn.transform(new GetAndSetINode(control(), mem, adr, newval, adr_type)); - } else if (kind == LS_cmpxchg) { - load_store = _gvn.transform(new CompareAndSwapINode(control(), mem, adr, newval, oldval)); - } else { - ShouldNotReachHere(); + switch(kind) { + case LS_get_add: + load_store = _gvn.transform(new GetAndAddINode(control(), mem, adr, newval, adr_type)); + break; + case LS_get_set: + load_store = _gvn.transform(new GetAndSetINode(control(), mem, adr, newval, adr_type)); + break; + case LS_cmp_swap_weak: + load_store = _gvn.transform(new WeakCompareAndSwapINode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_swap: + load_store = _gvn.transform(new CompareAndSwapINode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_exchange: + load_store = _gvn.transform(new CompareAndExchangeINode(control(), mem, adr, newval, oldval, adr_type, mo)); + break; + default: + ShouldNotReachHere(); } break; case T_LONG: - if (kind == LS_xadd) { - load_store = _gvn.transform(new GetAndAddLNode(control(), mem, adr, newval, adr_type)); - } else if (kind == LS_xchg) { - load_store = _gvn.transform(new GetAndSetLNode(control(), mem, adr, newval, adr_type)); - } else if (kind == LS_cmpxchg) { - load_store = _gvn.transform(new CompareAndSwapLNode(control(), mem, adr, newval, oldval)); - } else { - ShouldNotReachHere(); + switch(kind) { + case LS_get_add: + load_store = _gvn.transform(new GetAndAddLNode(control(), mem, adr, newval, adr_type)); + break; + case LS_get_set: + load_store = _gvn.transform(new GetAndSetLNode(control(), mem, adr, newval, adr_type)); + break; + case LS_cmp_swap_weak: + load_store = _gvn.transform(new WeakCompareAndSwapLNode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_swap: + load_store = _gvn.transform(new CompareAndSwapLNode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_exchange: + load_store = _gvn.transform(new CompareAndExchangeLNode(control(), mem, adr, newval, oldval, adr_type, mo)); + break; + default: + ShouldNotReachHere(); } break; case T_OBJECT: @@ -2713,65 +2934,109 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind newval = _gvn.makecon(TypePtr::NULL_PTR); // Reference stores need a store barrier. - if (kind == LS_xchg) { - // If pre-barrier must execute before the oop store, old value will require do_load here. - if (!can_move_pre_barrier()) { - pre_barrier(true /* do_load*/, - control(), base, adr, alias_idx, newval, value_type->make_oopptr(), - NULL /* pre_val*/, - T_OBJECT); - } // Else move pre_barrier to use load_store value, see below. - } else if (kind == LS_cmpxchg) { - // Same as for newval above: - if (_gvn.type(oldval) == TypePtr::NULL_PTR) { - oldval = _gvn.makecon(TypePtr::NULL_PTR); + switch(kind) { + case LS_get_set: { + // If pre-barrier must execute before the oop store, old value will require do_load here. + if (!can_move_pre_barrier()) { + pre_barrier(true /* do_load*/, + control(), base, adr, alias_idx, newval, value_type->make_oopptr(), + NULL /* pre_val*/, + T_OBJECT); + } // Else move pre_barrier to use load_store value, see below. + break; } - // The only known value which might get overwritten is oldval. - pre_barrier(false /* do_load */, - control(), NULL, NULL, max_juint, NULL, NULL, - oldval /* pre_val */, - T_OBJECT); - } else { - ShouldNotReachHere(); + case LS_cmp_swap_weak: + case LS_cmp_swap: + case LS_cmp_exchange: { + // Same as for newval above: + if (_gvn.type(oldval) == TypePtr::NULL_PTR) { + oldval = _gvn.makecon(TypePtr::NULL_PTR); + } + // The only known value which might get overwritten is oldval. + pre_barrier(false /* do_load */, + control(), NULL, NULL, max_juint, NULL, NULL, + oldval /* pre_val */, + T_OBJECT); + break; + } + default: + ShouldNotReachHere(); } #ifdef _LP64 if (adr->bottom_type()->is_ptr_to_narrowoop()) { Node *newval_enc = _gvn.transform(new EncodePNode(newval, newval->bottom_type()->make_narrowoop())); - if (kind == LS_xchg) { - load_store = _gvn.transform(new GetAndSetNNode(control(), mem, adr, - newval_enc, adr_type, value_type->make_narrowoop())); - } else { - assert(kind == LS_cmpxchg, "wrong LoadStore operation"); - Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop())); - load_store = _gvn.transform(new CompareAndSwapNNode(control(), mem, adr, - newval_enc, oldval_enc)); + + switch(kind) { + case LS_get_set: + load_store = _gvn.transform(new GetAndSetNNode(control(), mem, adr, newval_enc, adr_type, value_type->make_narrowoop())); + break; + case LS_cmp_swap_weak: { + Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop())); + load_store = _gvn.transform(new WeakCompareAndSwapNNode(control(), mem, adr, newval_enc, oldval_enc, mo)); + break; + } + case LS_cmp_swap: { + Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop())); + load_store = _gvn.transform(new CompareAndSwapNNode(control(), mem, adr, newval_enc, oldval_enc, mo)); + break; + } + case LS_cmp_exchange: { + Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop())); + load_store = _gvn.transform(new CompareAndExchangeNNode(control(), mem, adr, newval_enc, oldval_enc, adr_type, value_type->make_narrowoop(), mo)); + break; + } + default: + ShouldNotReachHere(); } } else #endif - { - if (kind == LS_xchg) { + switch (kind) { + case LS_get_set: load_store = _gvn.transform(new GetAndSetPNode(control(), mem, adr, newval, adr_type, value_type->is_oopptr())); - } else { - assert(kind == LS_cmpxchg, "wrong LoadStore operation"); - load_store = _gvn.transform(new CompareAndSwapPNode(control(), mem, adr, newval, oldval)); - } + break; + case LS_cmp_swap_weak: + load_store = _gvn.transform(new WeakCompareAndSwapPNode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_swap: + load_store = _gvn.transform(new CompareAndSwapPNode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_exchange: + load_store = _gvn.transform(new CompareAndExchangePNode(control(), mem, adr, newval, oldval, adr_type, value_type->is_oopptr(), mo)); + break; + default: + ShouldNotReachHere(); } - if (kind == LS_cmpxchg) { - // Emit the post barrier only when the actual store happened. - // This makes sense to check only for compareAndSet that can fail to set the value. - // CAS success path is marked more likely since we anticipate this is a performance - // critical path, while CAS failure path can use the penalty for going through unlikely - // path as backoff. Which is still better than doing a store barrier there. - IdealKit ideal(this); - ideal.if_then(load_store, BoolTest::ne, ideal.ConI(0), PROB_STATIC_FREQUENT); { - sync_kit(ideal); - post_barrier(ideal.ctrl(), load_store, base, adr, alias_idx, newval, T_OBJECT, true); - ideal.sync_kit(this); - } ideal.end_if(); - final_sync(ideal); - } else { - post_barrier(control(), load_store, base, adr, alias_idx, newval, T_OBJECT, true); + + // Emit the post barrier only when the actual store happened. This makes sense + // to check only for LS_cmp_* that can fail to set the value. + // LS_cmp_exchange does not produce any branches by default, so there is no + // boolean result to piggyback on. TODO: When we merge CompareAndSwap with + // CompareAndExchange and move branches here, it would make sense to conditionalize + // post_barriers for LS_cmp_exchange as well. + // + // CAS success path is marked more likely since we anticipate this is a performance + // critical path, while CAS failure path can use the penalty for going through unlikely + // path as backoff. Which is still better than doing a store barrier there. + switch (kind) { + case LS_get_set: + case LS_cmp_exchange: { + post_barrier(control(), load_store, base, adr, alias_idx, newval, T_OBJECT, true); + break; + } + case LS_cmp_swap_weak: + case LS_cmp_swap: { + IdealKit ideal(this); + ideal.if_then(load_store, BoolTest::ne, ideal.ConI(0), PROB_STATIC_FREQUENT); { + sync_kit(ideal); + post_barrier(ideal.ctrl(), load_store, base, adr, alias_idx, newval, T_OBJECT, true); + ideal.sync_kit(this); + } ideal.end_if(); + final_sync(ideal); + break; + } + default: + ShouldNotReachHere(); } break; default: @@ -2785,7 +3050,7 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind Node* proj = _gvn.transform(new SCMemProjNode(load_store)); set_memory(proj, alias_idx); - if (type == T_OBJECT && kind == LS_xchg) { + if (type == T_OBJECT && (kind == LS_get_set || kind == LS_cmp_exchange)) { #ifdef _LP64 if (adr->bottom_type()->is_ptr_to_narrowoop()) { load_store = _gvn.transform(new DecodeNNode(load_store, load_store->get_ptr_type())); @@ -2804,74 +3069,52 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind // Add the trailing membar surrounding the access insert_mem_bar(Op_MemBarCPUOrder); - insert_mem_bar(Op_MemBarAcquire); + + switch (access_kind) { + case Relaxed: + case Release: + break; // do nothing + case Acquire: + case Volatile: + insert_mem_bar(Op_MemBarAcquire); + break; + default: + ShouldNotReachHere(); + } assert(type2size[load_store->bottom_type()->basic_type()] == type2size[rtype], "result type should match"); set_result(load_store); return true; } -//----------------------------inline_unsafe_ordered_store---------------------- -// public native void Unsafe.putOrderedObject(Object o, long offset, Object x); -// public native void Unsafe.putOrderedInt(Object o, long offset, int x); -// public native void Unsafe.putOrderedLong(Object o, long offset, long x); -bool LibraryCallKit::inline_unsafe_ordered_store(BasicType type) { - // This is another variant of inline_unsafe_access, differing in - // that it always issues store-store ("release") barrier and ensures - // store-atomicity (which only matters for "long"). - - if (callee()->is_static()) return false; // caller must have the capability! - -#ifndef PRODUCT - { - ResourceMark rm; - // Check the signatures. - ciSignature* sig = callee()->signature(); -#ifdef ASSERT - BasicType rtype = sig->return_type()->basic_type(); - assert(rtype == T_VOID, "must return void"); - assert(sig->count() == 3, "has 3 arguments"); - assert(sig->type_at(0)->basic_type() == T_OBJECT, "base is object"); - assert(sig->type_at(1)->basic_type() == T_LONG, "offset is long"); -#endif // ASSERT +MemNode::MemOrd LibraryCallKit::access_kind_to_memord_LS(AccessKind kind, bool is_store) { + MemNode::MemOrd mo = MemNode::unset; + switch(kind) { + case Opaque: + case Relaxed: mo = MemNode::unordered; break; + case Acquire: mo = MemNode::acquire; break; + case Release: mo = MemNode::release; break; + case Volatile: mo = is_store ? MemNode::release : MemNode::acquire; break; + default: + ShouldNotReachHere(); } -#endif //PRODUCT + guarantee(mo != MemNode::unset, "Should select memory ordering"); + return mo; +} - C->set_has_unsafe_access(true); // Mark eventual nmethod as "unsafe". - - // Get arguments: - Node* receiver = argument(0); // type: oop - Node* base = argument(1); // type: oop - Node* offset = argument(2); // type: long - Node* val = argument(4); // type: oop, int, or long - - // Null check receiver. - receiver = null_check(receiver); - if (stopped()) { - return true; +MemNode::MemOrd LibraryCallKit::access_kind_to_memord(AccessKind kind) { + MemNode::MemOrd mo = MemNode::unset; + switch(kind) { + case Opaque: + case Relaxed: mo = MemNode::unordered; break; + case Acquire: mo = MemNode::acquire; break; + case Release: mo = MemNode::release; break; + case Volatile: mo = MemNode::seqcst; break; + default: + ShouldNotReachHere(); } - - // Build field offset expression. - assert(Unsafe_field_offset_to_byte_offset(11) == 11, "fieldOffset must be byte-scaled"); - // 32-bit machines ignore the high half of long offsets - offset = ConvL2X(offset); - Node* adr = make_unsafe_address(base, offset); - const TypePtr *adr_type = _gvn.type(adr)->isa_ptr(); - const Type *value_type = Type::get_const_basic_type(type); - Compile::AliasType* alias_type = C->alias_type(adr_type); - - insert_mem_bar(Op_MemBarRelease); - insert_mem_bar(Op_MemBarCPUOrder); - // Ensure that the store is atomic for longs: - const bool require_atomic_access = true; - Node* store; - if (type == T_OBJECT) // reference stores need a store barrier. - store = store_oop_to_unknown(control(), base, adr, adr_type, val, type, MemNode::release); - else { - store = store_to_memory(control(), adr, val, type, adr_type, MemNode::release, require_atomic_access); - } - insert_mem_bar(Op_MemBarCPUOrder); - return true; + guarantee(mo != MemNode::unset, "Should select memory ordering"); + return mo; } bool LibraryCallKit::inline_unsafe_fence(vmIntrinsics::ID id) { diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index 57568819107..8c077f11d5f 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -2417,6 +2417,14 @@ void IdealLoopTree::adjust_loop_exit_prob( PhaseIdealLoop *phase ) { ((bol->in(1)->Opcode() == Op_StorePConditional ) || (bol->in(1)->Opcode() == Op_StoreIConditional ) || (bol->in(1)->Opcode() == Op_StoreLConditional ) || + (bol->in(1)->Opcode() == Op_CompareAndExchangeI ) || + (bol->in(1)->Opcode() == Op_CompareAndExchangeL ) || + (bol->in(1)->Opcode() == Op_CompareAndExchangeP ) || + (bol->in(1)->Opcode() == Op_CompareAndExchangeN ) || + (bol->in(1)->Opcode() == Op_WeakCompareAndSwapI ) || + (bol->in(1)->Opcode() == Op_WeakCompareAndSwapL ) || + (bol->in(1)->Opcode() == Op_WeakCompareAndSwapP ) || + (bol->in(1)->Opcode() == Op_WeakCompareAndSwapN ) || (bol->in(1)->Opcode() == Op_CompareAndSwapI ) || (bol->in(1)->Opcode() == Op_CompareAndSwapL ) || (bol->in(1)->Opcode() == Op_CompareAndSwapP ) || diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index bb18a3da6d8..edb69afb43d 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -2307,6 +2307,14 @@ void Matcher::find_shared( Node *n ) { case Op_StorePConditional: case Op_StoreIConditional: case Op_StoreLConditional: + case Op_CompareAndExchangeI: + case Op_CompareAndExchangeL: + case Op_CompareAndExchangeP: + case Op_CompareAndExchangeN: + case Op_WeakCompareAndSwapI: + case Op_WeakCompareAndSwapL: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: case Op_CompareAndSwapI: case Op_CompareAndSwapL: case Op_CompareAndSwapP: @@ -2522,6 +2530,14 @@ bool Matcher::post_store_load_barrier(const Node* vmb) { // that a monitor exit operation contains a serializing instruction. if (xop == Op_MemBarVolatile || + xop == Op_CompareAndExchangeI || + xop == Op_CompareAndExchangeL || + xop == Op_CompareAndExchangeP || + xop == Op_CompareAndExchangeN || + xop == Op_WeakCompareAndSwapL || + xop == Op_WeakCompareAndSwapP || + xop == Op_WeakCompareAndSwapN || + xop == Op_WeakCompareAndSwapI || xop == Op_CompareAndSwapL || xop == Op_CompareAndSwapP || xop == Op_CompareAndSwapN || diff --git a/hotspot/src/share/vm/opto/memnode.hpp b/hotspot/src/share/vm/opto/memnode.hpp index 994b782dfbb..8d9cd71bc0a 100644 --- a/hotspot/src/share/vm/opto/memnode.hpp +++ b/hotspot/src/share/vm/opto/memnode.hpp @@ -56,7 +56,9 @@ public: }; typedef enum { unordered = 0, acquire, // Load has to acquire or be succeeded by MemBarAcquire. - release // Store has to release or be preceded by MemBarRelease. + release, // Store has to release or be preceded by MemBarRelease. + seqcst, // LoadStore has to have both acquire and release semantics. + unset // The memory ordering is not set (used for testing) } MemOrd; protected: MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at ) @@ -848,34 +850,121 @@ public: virtual uint ideal_reg() const { return Op_RegFlags; } }; +class CompareAndSwapNode : public LoadStoreConditionalNode { +private: + const MemNode::MemOrd _mem_ord; +public: + CompareAndSwapNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : LoadStoreConditionalNode(c, mem, adr, val, ex), _mem_ord(mem_ord) {} + MemNode::MemOrd order() const { + return _mem_ord; + } +}; + +class CompareAndExchangeNode : public LoadStoreNode { +private: + const MemNode::MemOrd _mem_ord; +public: + enum { + ExpectedIn = MemNode::ValueIn+1 // One more input than MemNode + }; + CompareAndExchangeNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord, const TypePtr* at, const Type* t) : + LoadStoreNode(c, mem, adr, val, at, t, 5), _mem_ord(mem_ord) { + init_req(ExpectedIn, ex ); + } + + MemNode::MemOrd order() const { + return _mem_ord; + } +}; //------------------------------CompareAndSwapLNode--------------------------- -class CompareAndSwapLNode : public LoadStoreConditionalNode { +class CompareAndSwapLNode : public CompareAndSwapNode { public: - CompareAndSwapLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex) : LoadStoreConditionalNode(c, mem, adr, val, ex) { } + CompareAndSwapLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } virtual int Opcode() const; }; //------------------------------CompareAndSwapINode--------------------------- -class CompareAndSwapINode : public LoadStoreConditionalNode { +class CompareAndSwapINode : public CompareAndSwapNode { public: - CompareAndSwapINode( Node *c, Node *mem, Node *adr, Node *val, Node *ex) : LoadStoreConditionalNode(c, mem, adr, val, ex) { } + CompareAndSwapINode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } virtual int Opcode() const; }; //------------------------------CompareAndSwapPNode--------------------------- -class CompareAndSwapPNode : public LoadStoreConditionalNode { +class CompareAndSwapPNode : public CompareAndSwapNode { public: - CompareAndSwapPNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex) : LoadStoreConditionalNode(c, mem, adr, val, ex) { } + CompareAndSwapPNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } virtual int Opcode() const; }; //------------------------------CompareAndSwapNNode--------------------------- -class CompareAndSwapNNode : public LoadStoreConditionalNode { +class CompareAndSwapNNode : public CompareAndSwapNode { public: - CompareAndSwapNNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex) : LoadStoreConditionalNode(c, mem, adr, val, ex) { } + CompareAndSwapNNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + + +//------------------------------WeakCompareAndSwapLNode--------------------------- +class WeakCompareAndSwapLNode : public CompareAndSwapNode { +public: + WeakCompareAndSwapLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + + +//------------------------------WeakCompareAndSwapINode--------------------------- +class WeakCompareAndSwapINode : public CompareAndSwapNode { +public: + WeakCompareAndSwapINode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + + +//------------------------------WeakCompareAndSwapPNode--------------------------- +class WeakCompareAndSwapPNode : public CompareAndSwapNode { +public: + WeakCompareAndSwapPNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + +//------------------------------WeakCompareAndSwapNNode--------------------------- +class WeakCompareAndSwapNNode : public CompareAndSwapNode { +public: + WeakCompareAndSwapNNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + +//------------------------------CompareAndExchangeLNode--------------------------- +class CompareAndExchangeLNode : public CompareAndExchangeNode { +public: + CompareAndExchangeLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, MemNode::MemOrd mem_ord) : CompareAndExchangeNode(c, mem, adr, val, ex, mem_ord, at, TypeLong::LONG) { } + virtual int Opcode() const; +}; + + +//------------------------------CompareAndExchangeINode--------------------------- +class CompareAndExchangeINode : public CompareAndExchangeNode { +public: + CompareAndExchangeINode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, MemNode::MemOrd mem_ord) : CompareAndExchangeNode(c, mem, adr, val, ex, mem_ord, at, TypeInt::INT) { } + virtual int Opcode() const; +}; + + +//------------------------------CompareAndExchangePNode--------------------------- +class CompareAndExchangePNode : public CompareAndExchangeNode { +public: + CompareAndExchangePNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, const Type* t, MemNode::MemOrd mem_ord) : CompareAndExchangeNode(c, mem, adr, val, ex, mem_ord, at, t) { } + virtual int Opcode() const; +}; + +//------------------------------CompareAndExchangeNNode--------------------------- +class CompareAndExchangeNNode : public CompareAndExchangeNode { +public: + CompareAndExchangeNNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, const Type* t, MemNode::MemOrd mem_ord) : CompareAndExchangeNode(c, mem, adr, val, ex, mem_ord, at, t) { } virtual int Opcode() const; }; diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp index b7900ad276d..b14505d3c4c 100644 --- a/hotspot/src/share/vm/opto/node.hpp +++ b/hotspot/src/share/vm/opto/node.hpp @@ -60,6 +60,8 @@ class CmpNode; class CodeBuffer; class ConstraintCastNode; class ConNode; +class CompareAndSwapNode; +class CompareAndExchangeNode; class CountedLoopNode; class CountedLoopEndNode; class DecodeNarrowPtrNode; @@ -679,6 +681,9 @@ public: DEFINE_CLASS_ID(Store, Mem, 1) DEFINE_CLASS_ID(StoreVector, Store, 0) DEFINE_CLASS_ID(LoadStore, Mem, 2) + DEFINE_CLASS_ID(LoadStoreConditional, LoadStore, 0) + DEFINE_CLASS_ID(CompareAndSwap, LoadStoreConditional, 0) + DEFINE_CLASS_ID(CompareAndExchangeNode, LoadStore, 1) DEFINE_CLASS_ID(Region, Node, 5) DEFINE_CLASS_ID(Loop, Region, 0) diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp index 84d24626a15..cdd4334e229 100644 --- a/hotspot/src/share/vm/prims/unsafe.cpp +++ b/hotspot/src/share/vm/prims/unsafe.cpp @@ -1117,6 +1117,44 @@ UNSAFE_END // JSR166 ------------------------------------------------------------------ +UNSAFE_ENTRY(jobject, Unsafe_CompareAndExchangeObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h)) + UnsafeWrapper("Unsafe_CompareAndExchangeObject"); + oop x = JNIHandles::resolve(x_h); + oop e = JNIHandles::resolve(e_h); + oop p = JNIHandles::resolve(obj); + HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset); + oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e, true); + if (res == e) + update_barrier_set((void*)addr, x); + return JNIHandles::make_local(env, res); +UNSAFE_END + +UNSAFE_ENTRY(jint, Unsafe_CompareAndExchangeInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) + UnsafeWrapper("Unsafe_CompareAndExchangeInt"); + oop p = JNIHandles::resolve(obj); + jint* addr = (jint *) index_oop_from_field_offset_long(p, offset); + return (jint)(Atomic::cmpxchg(x, addr, e)); +UNSAFE_END + +UNSAFE_ENTRY(jlong, Unsafe_CompareAndExchangeLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x)) + UnsafeWrapper("Unsafe_CompareAndExchangeLong"); + Handle p (THREAD, JNIHandles::resolve(obj)); + jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset)); +#ifdef SUPPORTS_NATIVE_CX8 + return (jlong)(Atomic::cmpxchg(x, addr, e)); +#else + if (VM_Version::supports_cx8()) + return (jlong)(Atomic::cmpxchg(x, addr, e)); + else { + MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag); + jlong val = Atomic::load(addr); + if (val == e) + Atomic::store(x, addr); + return val; + } +#endif +UNSAFE_END + UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h)) UnsafeWrapper("Unsafe_CompareAndSwapObject"); oop x = JNIHandles::resolve(x_h); @@ -1384,6 +1422,10 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = { {CC "compareAndSwapObject", CC "(" OBJ "J" OBJ "" OBJ ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, {CC "compareAndSwapInt", CC "(" OBJ "J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, {CC "compareAndSwapLong", CC "(" OBJ "J""J""J"")Z", FN_PTR(Unsafe_CompareAndSwapLong)}, + {CC "compareAndExchangeObjectVolatile", CC "(" OBJ "J" OBJ "" OBJ ")" OBJ, FN_PTR(Unsafe_CompareAndExchangeObject)}, + {CC "compareAndExchangeIntVolatile", CC "(" OBJ "J""I""I"")I", FN_PTR(Unsafe_CompareAndExchangeInt)}, + {CC "compareAndExchangeLongVolatile", CC "(" OBJ "J""J""J"")J", FN_PTR(Unsafe_CompareAndExchangeLong)}, + {CC "putOrderedObject", CC "(" OBJ "J" OBJ ")V", FN_PTR(Unsafe_SetOrderedObject)}, {CC "putOrderedInt", CC "(" OBJ "JI)V", FN_PTR(Unsafe_SetOrderedInt)}, {CC "putOrderedLong", CC "(" OBJ "JJ)V", FN_PTR(Unsafe_SetOrderedLong)}, diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 0778abc2f7a..84d2c6ebd3b 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -2005,10 +2005,20 @@ typedef CompactHashtable SymbolCompactHashTable; declare_c2_type(LoadStoreNode, Node) \ declare_c2_type(StorePConditionalNode, LoadStoreNode) \ declare_c2_type(StoreLConditionalNode, LoadStoreNode) \ - declare_c2_type(CompareAndSwapLNode, LoadStoreNode) \ - declare_c2_type(CompareAndSwapINode, LoadStoreNode) \ - declare_c2_type(CompareAndSwapPNode, LoadStoreNode) \ - declare_c2_type(CompareAndSwapNNode, LoadStoreNode) \ + declare_c2_type(CompareAndSwapNode, LoadStoreConditionalNode) \ + declare_c2_type(CompareAndSwapLNode, CompareAndSwapNode) \ + declare_c2_type(CompareAndSwapINode, CompareAndSwapNode) \ + declare_c2_type(CompareAndSwapPNode, CompareAndSwapNode) \ + declare_c2_type(CompareAndSwapNNode, CompareAndSwapNode) \ + declare_c2_type(WeakCompareAndSwapLNode, CompareAndSwapNode) \ + declare_c2_type(WeakCompareAndSwapINode, CompareAndSwapNode) \ + declare_c2_type(WeakCompareAndSwapPNode, CompareAndSwapNode) \ + declare_c2_type(WeakCompareAndSwapNNode, CompareAndSwapNode) \ + declare_c2_type(CompareAndExchangeNode, LoadStoreNode) \ + declare_c2_type(CompareAndExchangeLNode, CompareAndExchangeNode) \ + declare_c2_type(CompareAndExchangeINode, CompareAndExchangeNode) \ + declare_c2_type(CompareAndExchangePNode, CompareAndExchangeNode) \ + declare_c2_type(CompareAndExchangeNNode, CompareAndExchangeNode) \ declare_c2_type(MulNode, Node) \ declare_c2_type(MulINode, MulNode) \ declare_c2_type(MulLNode, MulNode) \ diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java index 1f19d4c14da..f8b82d21549 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java @@ -128,6 +128,20 @@ public class JdkInternalMiscUnsafeAccessTestBoolean { } + // Lazy + { + UNSAFE.putBooleanRelease(base, offset, true); + boolean x = UNSAFE.getBooleanAcquire(base, offset); + assertEquals(x, true, "putRelease boolean value"); + } + + // Opaque + { + UNSAFE.putBooleanOpaque(base, offset, false); + boolean x = UNSAFE.getBooleanOpaque(base, offset); + assertEquals(x, false, "putOpaque boolean value"); + } + } diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java index a3ffa6fb8ab..edc6f9ad859 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestByte { } + // Lazy + { + UNSAFE.putByteRelease(base, offset, (byte)1); + byte x = UNSAFE.getByteAcquire(base, offset); + assertEquals(x, (byte)1, "putRelease byte value"); + } + + // Opaque + { + UNSAFE.putByteOpaque(base, offset, (byte)2); + byte x = UNSAFE.getByteOpaque(base, offset); + assertEquals(x, (byte)2, "putOpaque byte value"); + } + } diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java index b148aee5c8a..b63b1716ffa 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestChar { } + // Lazy + { + UNSAFE.putCharRelease(base, offset, 'a'); + char x = UNSAFE.getCharAcquire(base, offset); + assertEquals(x, 'a', "putRelease char value"); + } + + // Opaque + { + UNSAFE.putCharOpaque(base, offset, 'b'); + char x = UNSAFE.getCharOpaque(base, offset); + assertEquals(x, 'b', "putOpaque char value"); + } + // Unaligned { UNSAFE.putCharUnaligned(base, offset, 'b'); diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java index 3ea637178ac..2309269f473 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestDouble { } + // Lazy + { + UNSAFE.putDoubleRelease(base, offset, 1.0d); + double x = UNSAFE.getDoubleAcquire(base, offset); + assertEquals(x, 1.0d, "putRelease double value"); + } + + // Opaque + { + UNSAFE.putDoubleOpaque(base, offset, 2.0d); + double x = UNSAFE.getDoubleOpaque(base, offset); + assertEquals(x, 2.0d, "putOpaque double value"); + } + } diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java index a2e313620fb..07f537f4c5e 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestFloat { } + // Lazy + { + UNSAFE.putFloatRelease(base, offset, 1.0f); + float x = UNSAFE.getFloatAcquire(base, offset); + assertEquals(x, 1.0f, "putRelease float value"); + } + + // Opaque + { + UNSAFE.putFloatOpaque(base, offset, 2.0f); + float x = UNSAFE.getFloatOpaque(base, offset); + assertEquals(x, 2.0f, "putOpaque float value"); + } + } diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java index 1ea024f1320..0d8bc7e4291 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java @@ -163,6 +163,20 @@ public class JdkInternalMiscUnsafeAccessTestInt { assertEquals(x, 1, "putRelease int value"); } + // Lazy + { + UNSAFE.putIntRelease(base, offset, 1); + int x = UNSAFE.getIntAcquire(base, offset); + assertEquals(x, 1, "putRelease int value"); + } + + // Opaque + { + UNSAFE.putIntOpaque(base, offset, 2); + int x = UNSAFE.getIntOpaque(base, offset); + assertEquals(x, 2, "putOpaque int value"); + } + // Unaligned { UNSAFE.putIntUnaligned(base, offset, 2); @@ -199,6 +213,70 @@ public class JdkInternalMiscUnsafeAccessTestInt { assertEquals(x, 2, "failing compareAndSwap int value"); } + // Advanced compare + { + int r = UNSAFE.compareAndExchangeIntVolatile(base, offset, 2, 1); + assertEquals(r, 2, "success compareAndExchangeVolatile int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "success compareAndExchangeVolatile int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntVolatile(base, offset, 2, 3); + assertEquals(r, 1, "failing compareAndExchangeVolatile int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "failing compareAndExchangeVolatile int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntAcquire(base, offset, 1, 2); + assertEquals(r, 1, "success compareAndExchangeAcquire int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "success compareAndExchangeAcquire int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntAcquire(base, offset, 1, 3); + assertEquals(r, 2, "failing compareAndExchangeAcquire int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "failing compareAndExchangeAcquire int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntRelease(base, offset, 2, 1); + assertEquals(r, 2, "success compareAndExchangeRelease int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "success compareAndExchangeRelease int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntRelease(base, offset, 2, 3); + assertEquals(r, 1, "failing compareAndExchangeRelease int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "failing compareAndExchangeRelease int value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapInt(base, offset, 1, 2); + assertEquals(r, true, "weakCompareAndSwap int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "weakCompareAndSwap int value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapIntAcquire(base, offset, 2, 1); + assertEquals(r, true, "weakCompareAndSwapAcquire int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "weakCompareAndSwapAcquire int"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapIntRelease(base, offset, 1, 2); + assertEquals(r, true, "weakCompareAndSwapRelease int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "weakCompareAndSwapRelease int"); + } + // Compare set and get { int o = UNSAFE.getAndSetInt(base, offset, 1); diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java index 0c5262019b1..4460b4452e4 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java @@ -163,6 +163,20 @@ public class JdkInternalMiscUnsafeAccessTestLong { assertEquals(x, 1L, "putRelease long value"); } + // Lazy + { + UNSAFE.putLongRelease(base, offset, 1L); + long x = UNSAFE.getLongAcquire(base, offset); + assertEquals(x, 1L, "putRelease long value"); + } + + // Opaque + { + UNSAFE.putLongOpaque(base, offset, 2L); + long x = UNSAFE.getLongOpaque(base, offset); + assertEquals(x, 2L, "putOpaque long value"); + } + // Unaligned { UNSAFE.putLongUnaligned(base, offset, 2L); @@ -199,6 +213,70 @@ public class JdkInternalMiscUnsafeAccessTestLong { assertEquals(x, 2L, "failing compareAndSwap long value"); } + // Advanced compare + { + long r = UNSAFE.compareAndExchangeLongVolatile(base, offset, 2L, 1L); + assertEquals(r, 2L, "success compareAndExchangeVolatile long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "success compareAndExchangeVolatile long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongVolatile(base, offset, 2L, 3L); + assertEquals(r, 1L, "failing compareAndExchangeVolatile long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "failing compareAndExchangeVolatile long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongAcquire(base, offset, 1L, 2L); + assertEquals(r, 1L, "success compareAndExchangeAcquire long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "success compareAndExchangeAcquire long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongAcquire(base, offset, 1L, 3L); + assertEquals(r, 2L, "failing compareAndExchangeAcquire long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "failing compareAndExchangeAcquire long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongRelease(base, offset, 2L, 1L); + assertEquals(r, 2L, "success compareAndExchangeRelease long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "success compareAndExchangeRelease long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongRelease(base, offset, 2L, 3L); + assertEquals(r, 1L, "failing compareAndExchangeRelease long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "failing compareAndExchangeRelease long value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapLong(base, offset, 1L, 2L); + assertEquals(r, true, "weakCompareAndSwap long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "weakCompareAndSwap long value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapLongAcquire(base, offset, 2L, 1L); + assertEquals(r, true, "weakCompareAndSwapAcquire long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "weakCompareAndSwapAcquire long"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapLongRelease(base, offset, 1L, 2L); + assertEquals(r, true, "weakCompareAndSwapRelease long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "weakCompareAndSwapRelease long"); + } + // Compare set and get { long o = UNSAFE.getAndSetLong(base, offset, 1L); diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java index c23cffd02ad..98afe49f6fa 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java @@ -134,6 +134,20 @@ public class JdkInternalMiscUnsafeAccessTestObject { assertEquals(x, "foo", "putRelease Object value"); } + // Lazy + { + UNSAFE.putObjectRelease(base, offset, "foo"); + Object x = UNSAFE.getObjectAcquire(base, offset); + assertEquals(x, "foo", "putRelease Object value"); + } + + // Opaque + { + UNSAFE.putObjectOpaque(base, offset, "bar"); + Object x = UNSAFE.getObjectOpaque(base, offset); + assertEquals(x, "bar", "putOpaque Object value"); + } + UNSAFE.putObject(base, offset, "foo"); @@ -152,6 +166,70 @@ public class JdkInternalMiscUnsafeAccessTestObject { assertEquals(x, "bar", "failing compareAndSwap Object value"); } + // Advanced compare + { + Object r = UNSAFE.compareAndExchangeObjectVolatile(base, offset, "bar", "foo"); + assertEquals(r, "bar", "success compareAndExchangeVolatile Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "success compareAndExchangeVolatile Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectVolatile(base, offset, "bar", "baz"); + assertEquals(r, "foo", "failing compareAndExchangeVolatile Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "failing compareAndExchangeVolatile Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectAcquire(base, offset, "foo", "bar"); + assertEquals(r, "foo", "success compareAndExchangeAcquire Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "success compareAndExchangeAcquire Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectAcquire(base, offset, "foo", "baz"); + assertEquals(r, "bar", "failing compareAndExchangeAcquire Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "failing compareAndExchangeAcquire Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectRelease(base, offset, "bar", "foo"); + assertEquals(r, "bar", "success compareAndExchangeRelease Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "success compareAndExchangeRelease Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectRelease(base, offset, "bar", "baz"); + assertEquals(r, "foo", "failing compareAndExchangeRelease Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "failing compareAndExchangeRelease Object value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapObject(base, offset, "foo", "bar"); + assertEquals(r, true, "weakCompareAndSwap Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "weakCompareAndSwap Object value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapObjectAcquire(base, offset, "bar", "foo"); + assertEquals(r, true, "weakCompareAndSwapAcquire Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "weakCompareAndSwapAcquire Object"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapObjectRelease(base, offset, "foo", "bar"); + assertEquals(r, true, "weakCompareAndSwapRelease Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "weakCompareAndSwapRelease Object"); + } + // Compare set and get { Object o = UNSAFE.getAndSetObject(base, offset, "foo"); diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java index 40a20789769..600425dc913 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestShort { } + // Lazy + { + UNSAFE.putShortRelease(base, offset, (short)1); + short x = UNSAFE.getShortAcquire(base, offset); + assertEquals(x, (short)1, "putRelease short value"); + } + + // Opaque + { + UNSAFE.putShortOpaque(base, offset, (short)2); + short x = UNSAFE.getShortOpaque(base, offset); + assertEquals(x, (short)2, "putOpaque short value"); + } + // Unaligned { UNSAFE.putShortUnaligned(base, offset, (short)2); diff --git a/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template b/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template index fcc74e325b0..4553635a158 100644 --- a/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template +++ b/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template @@ -169,6 +169,22 @@ public class $Qualifier$UnsafeAccessTest$Type$ { } #end[Ordered] +#if[JdkInternalMisc] + // Lazy + { + UNSAFE.put$Type$Release(base, offset, $value1$); + $type$ x = UNSAFE.get$Type$Acquire(base, offset); + assertEquals(x, $value1$, "putRelease $type$ value"); + } + + // Opaque + { + UNSAFE.put$Type$Opaque(base, offset, $value2$); + $type$ x = UNSAFE.get$Type$Opaque(base, offset); + assertEquals(x, $value2$, "putOpaque $type$ value"); + } +#end[JdkInternalMisc] + #if[JdkInternalMisc] #if[Unaligned] // Unaligned @@ -210,6 +226,72 @@ public class $Qualifier$UnsafeAccessTest$Type$ { assertEquals(x, $value2$, "failing compareAndSwap $type$ value"); } +#if[JdkInternalMisc] + // Advanced compare + { + $type$ r = UNSAFE.compareAndExchange$Type$Volatile(base, offset, $value2$, $value1$); + assertEquals(r, $value2$, "success compareAndExchangeVolatile $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "success compareAndExchangeVolatile $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Volatile(base, offset, $value2$, $value3$); + assertEquals(r, $value1$, "failing compareAndExchangeVolatile $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "failing compareAndExchangeVolatile $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Acquire(base, offset, $value1$, $value2$); + assertEquals(r, $value1$, "success compareAndExchangeAcquire $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "success compareAndExchangeAcquire $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Acquire(base, offset, $value1$, $value3$); + assertEquals(r, $value2$, "failing compareAndExchangeAcquire $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "failing compareAndExchangeAcquire $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Release(base, offset, $value2$, $value1$); + assertEquals(r, $value2$, "success compareAndExchangeRelease $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "success compareAndExchangeRelease $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Release(base, offset, $value2$, $value3$); + assertEquals(r, $value1$, "failing compareAndExchangeRelease $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "failing compareAndExchangeRelease $type$ value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwap$Type$(base, offset, $value1$, $value2$); + assertEquals(r, true, "weakCompareAndSwap $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "weakCompareAndSwap $type$ value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwap$Type$Acquire(base, offset, $value2$, $value1$); + assertEquals(r, true, "weakCompareAndSwapAcquire $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "weakCompareAndSwapAcquire $type$"); + } + + { + boolean r = UNSAFE.weakCompareAndSwap$Type$Release(base, offset, $value1$, $value2$); + assertEquals(r, true, "weakCompareAndSwapRelease $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "weakCompareAndSwapRelease $type$"); + } +#end[JdkInternalMisc] + // Compare set and get { $type$ o = UNSAFE.getAndSet$Type$(base, offset, $value1$); @@ -244,4 +326,5 @@ public class $Qualifier$UnsafeAccessTest$Type$ { } #end[!boolean] #end[!Object] -} \ No newline at end of file +} + diff --git a/hotspot/test/compiler/unsafe/generate-unsafe-tests.sh b/hotspot/test/compiler/unsafe/generate-unsafe-tests.sh new file mode 100644 index 00000000000..a20c45afa86 --- /dev/null +++ b/hotspot/test/compiler/unsafe/generate-unsafe-tests.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +javac -d . ../../../../jdk/make/src/classes/build/tools/spp/Spp.java + +SPP=build.tools.spp.Spp + +# Generates unsafe access tests for objects and all primitive types +# $1 = package name to Unsafe, sun.misc | jdk.internal.misc +# $2 = test class qualifier name, SunMisc | JdkInternalMisc +function generate { + package=$1 + Qualifier=$2 + + for type in boolean byte short char int long float double Object + do + Type="$(tr '[:lower:]' '[:upper:]' <<< ${type:0:1})${type:1}" + args="-K$type -Dtype=$type -DType=$Type" + + case $type in + Object|int|long) + args="$args -KCAS -KOrdered" + ;; + esac + + case $type in + int|long) + args="$args -KAtomicAdd" + ;; + esac + + case $type in + short|char|int|long) + args="$args -KUnaligned" + ;; + esac + + case $type in + boolean) + value1=true + value2=false + value3=false + ;; + byte) + value1=(byte)1 + value2=(byte)2 + value3=(byte)3 + ;; + short) + value1=(short)1 + value2=(short)2 + value3=(short)3 + ;; + char) + value1=\'a\' + value2=\'b\' + value3=\'c\' + ;; + int) + value1=1 + value2=2 + value3=3 + ;; + long) + value1=1L + value2=2L + value3=3L + ;; + float) + value1=1.0f + value2=2.0f + value3=3.0f + ;; + double) + value1=1.0d + value2=2.0d + value3=3.0d + ;; + Object) + value1=\"foo\" + value2=\"bar\" + value3=\"baz\" + ;; + esac + + args="$args -Dvalue1=$value1 -Dvalue2=$value2 -Dvalue3=$value3" + + echo $args + + java $SPP -nel -K$Qualifier -Dpackage=$package -DQualifier=$Qualifier \ + $args < X-UnsafeAccessTest.java.template > ${Qualifier}UnsafeAccessTest${Type}.java + done +} + +generate sun.misc SunMisc +generate jdk.internal.misc JdkInternalMisc + +rm -fr build \ No newline at end of file From 6e26b67678d236ccbffaa4aabc9348738f3b9438 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 24 Feb 2016 18:43:51 +0300 Subject: [PATCH 031/183] 8150514: C1 crashes in Canonicalizer::do_ArrayLength() after fix for JDK-8150102 Reviewed-by: thartmann, vlivanov --- hotspot/src/share/vm/c1/c1_Canonicalizer.cpp | 5 +- .../compiler/c1/CanonicalizeArrayLength.java | 154 ++++++++++++++++++ 2 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 hotspot/test/compiler/c1/CanonicalizeArrayLength.java diff --git a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp index 48b814531e4..f6e5baa0c28 100644 --- a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp +++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp @@ -239,7 +239,10 @@ void Canonicalizer::do_ArrayLength (ArrayLength* x) { } else if ((ct = x->array()->as_Constant()) != NULL) { // Constant arrays have constant lengths. - set_constant(ct->type()->as_ArrayConstant()->value()->length()); + ArrayConstant* cnst = ct->type()->as_ArrayConstant(); + if (cnst != NULL) { + set_constant(cnst->value()->length()); + } #ifdef ASSERT } else { diff --git a/hotspot/test/compiler/c1/CanonicalizeArrayLength.java b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java new file mode 100644 index 00000000000..f8de9e595c9 --- /dev/null +++ b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8150102 8150514 + * @summary C1 crashes in Canonicalizer::do_ArrayLength() after fix for JDK-8150102 + * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation CanonicalizeArrayLength + * + */ + +public class CanonicalizeArrayLength { + int[] arr = new int[42]; + int[] arrNull = null; + + final int[] finalArr = new int[42]; + final int[] finalArrNull = null; + + static int[] staticArr = new int[42]; + static int[] staticArrNull = null; + + static final int[] staticFinalArr = new int[42]; + static final int[] staticFinalArrNull = null; + + public static void main(String... args) { + CanonicalizeArrayLength t = new CanonicalizeArrayLength(); + for (int i = 0; i < 20000; i++) { + if (t.testLocal() != 42) + throw new IllegalStateException(); + if (t.testLocalNull() != 42) + throw new IllegalStateException(); + if (t.testField() != 42) + throw new IllegalStateException(); + if (t.testFieldNull() != 42) + throw new IllegalStateException(); + if (t.testFinalField() != 42) + throw new IllegalStateException(); + if (t.testFinalFieldNull() != 42) + throw new IllegalStateException(); + if (t.testStaticField() != 42) + throw new IllegalStateException(); + if (t.testStaticFieldNull() != 42) + throw new IllegalStateException(); + if (t.testStaticFinalField() != 42) + throw new IllegalStateException(); + if (t.testStaticFinalFieldNull() != 42) + throw new IllegalStateException(); + } + } + + int testField() { + try { + return arr.length; + } catch (Throwable t) { + return -1; + } + } + + int testFieldNull() { + try { + return arrNull.length; + } catch (Throwable t) { + return 42; + } + } + + int testFinalField() { + try { + return finalArr.length; + } catch (Throwable t) { + return -1; + } + } + + int testFinalFieldNull() { + try { + return finalArrNull.length; + } catch (Throwable t) { + return 42; + } + } + + int testStaticField() { + try { + return staticArr.length; + } catch (Throwable t) { + return -1; + } + } + + int testStaticFieldNull() { + try { + return staticArrNull.length; + } catch (Throwable t) { + return 42; + } + } + + int testStaticFinalField() { + try { + return staticFinalArr.length; + } catch (Throwable t) { + return -1; + } + } + + int testStaticFinalFieldNull() { + try { + return staticFinalArrNull.length; + } catch (Throwable t) { + return 42; + } + } + + int testLocal() { + int[] arr = new int[42]; + try { + return arr.length; + } catch (Throwable t) { + return -1; + } + } + + int testLocalNull() { + int[] arrNull = null; + try { + return arrNull.length; + } catch (Throwable t) { + return 42; + } + } + + +} From 52c7cb7221cac7faf2ba195ef24265ce3e4559eb Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Thu, 25 Feb 2016 08:47:57 +0100 Subject: [PATCH 032/183] 8150441: CompileTask::print_impl() is broken after JDK-8146905 Timestamps should be explicitly initialized. Reviewed-by: dholmes --- hotspot/src/share/vm/utilities/vmError.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index ee6ad0e5ddb..2d0942349be 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -1121,6 +1121,10 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt if (first_error_tid == -1 && Atomic::cmpxchg_ptr(mytid, &first_error_tid, -1) == -1) { + // Initialize time stamps to use the same base. + out.time_stamp().update_to(1); + log.time_stamp().update_to(1); + _id = id; _message = message; _thread = thread; From e09bb29c2d6e11a78c8f59d9bf4f594207aa93cb Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Thu, 25 Feb 2016 10:42:42 +0100 Subject: [PATCH 033/183] 8148159: [TESTBUG] TestCompilerDirectivesCompatibility tests fails on non-tiered server VMs Add whitebox for checking available compilers Reviewed-by: kvn --- hotspot/src/share/vm/prims/whitebox.cpp | 10 ++-- ...stCompilerDirectivesCompatibilityBase.java | 51 +++++++++++-------- ...ilerDirectivesCompatibilityCommandOff.java | 39 +++++++------- ...pilerDirectivesCompatibilityCommandOn.java | 39 +++++++------- ...stCompilerDirectivesCompatibilityFlag.java | 39 +++++++------- 5 files changed, 94 insertions(+), 84 deletions(-) diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 407d7249125..776df026f7d 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -644,12 +644,12 @@ WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobjec return (mh->queued_for_compilation() || nm != NULL); WB_END -WB_ENTRY(jboolean, WB_ShouldPrintAssembly(JNIEnv* env, jobject o, jobject method)) +WB_ENTRY(jboolean, WB_ShouldPrintAssembly(JNIEnv* env, jobject o, jobject method, jint comp_level)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION_(env, JNI_FALSE); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - DirectiveSet* directive = DirectivesStack::getMatchingDirective(mh, CompileBroker::compiler(CompLevel_simple)); + DirectiveSet* directive = DirectivesStack::getMatchingDirective(mh, CompileBroker::compiler(comp_level)); bool result = directive->PrintAssemblyOption; DirectivesStack::release(directive); @@ -1556,8 +1556,8 @@ static JNINativeMethod methods[] = { #endif // INCLUDE_NMT {CC"deoptimizeFrames", CC"(Z)I", (void*)&WB_DeoptimizeFrames }, {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, - {CC"deoptimizeMethod0", CC"(Ljava/lang/reflect/Executable;Z)I", - (void*)&WB_DeoptimizeMethod }, + {CC"deoptimizeMethod0", CC"(Ljava/lang/reflect/Executable;Z)I", + (void*)&WB_DeoptimizeMethod }, {CC"isMethodCompiled0", CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_IsMethodCompiled }, {CC"isMethodCompilable0", CC"(Ljava/lang/reflect/Executable;IZ)Z", @@ -1592,7 +1592,7 @@ static JNINativeMethod methods[] = { CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)I", (void*)&WB_MatchesInline}, {CC"shouldPrintAssembly", - CC"(Ljava/lang/reflect/Executable;)Z", + CC"(Ljava/lang/reflect/Executable;I)Z", (void*)&WB_ShouldPrintAssembly}, {CC"isConstantVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsConstantVMFlag}, diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java index 283003afde6..ff5f70eceaa 100644 --- a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java @@ -24,25 +24,26 @@ /* * @test TestCompilerDirectivesCompatibilityBase * @bug 8137167 - * @library /testlibrary /test/lib + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @build sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityBase + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityBase * @summary Test compiler control compatibility with compile command */ +import compiler.testlibrary.CompilerUtils; +import compiler.whitebox.CompilerWhiteBoxTest; import jdk.test.lib.dcmd.CommandExecutor; import jdk.test.lib.dcmd.JMXExecutor; - import org.testng.annotations.Test; import org.testng.Assert; - import sun.hotspot.WhiteBox; import java.io.BufferedReader; @@ -64,32 +65,38 @@ public class TestCompilerDirectivesCompatibilityBase { method = getMethod(TestCompilerDirectivesCompatibilityBase.class, "helper"); nomatch = getMethod(TestCompilerDirectivesCompatibilityBase.class, "another"); - testCompatibility(executor); + int[] levels = CompilerUtils.getAvailableCompilationLevels(); + for (int complevel : levels) { + // Only test the major compilers, ignore profiling levels + if (complevel == CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE || complevel == CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION){ + testCompatibility(executor, complevel); + } + } } - public void testCompatibility(CommandExecutor executor) throws Exception { + public void testCompatibility(CommandExecutor executor, int comp_level) throws Exception { // Call all validation twice to catch error when overwriting a directive // Flag is default off expect(!WB.getBooleanVMFlag("PrintAssembly")); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); // load directives that turn it on executor.execute("Compiler.directives_add " + control_on); - expect(WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); // remove and see that it is true again executor.execute("Compiler.directives_remove"); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); } public void expect(boolean test) throws Exception { diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java index a2922c8a2d9..661b06036c0 100644 --- a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java @@ -24,16 +24,17 @@ /* * @test TestCompilerDirectivesCompatibilityCommandOff * @bug 8137167 - * @library /testlibrary /test/lib + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @build sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions * -XX:-PrintAssembly -XX:CompileCommand=option,*.helper,bool,PrintAssembly,false * -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityCommandOff * @summary Test compiler control compatibility with compile command @@ -55,27 +56,27 @@ import java.util.Objects; public class TestCompilerDirectivesCompatibilityCommandOff extends TestCompilerDirectivesCompatibilityBase { - public void testCompatibility(CommandExecutor executor) throws Exception { + public void testCompatibility(CommandExecutor executor, int comp_level) throws Exception { // Call all validation twice to catch error when overwriting a directive // Flag is default off - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); // load directives that turn it on executor.execute("Compiler.directives_add " + control_on); - expect(WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); // remove and see that it is false again executor.execute("Compiler.directives_remove"); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); } } diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java index 0123c282b11..8fd0eec6d53 100644 --- a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java @@ -24,16 +24,17 @@ /* * @test TestCompilerDirectivesCompatibilityCommandOn * @bug 8137167 - * @library /testlibrary /test/lib + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @build sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions * -XX:-PrintAssembly -XX:CompileCommand=print,*.* -XX:+WhiteBoxAPI * TestCompilerDirectivesCompatibilityCommandOn * @summary Test compiler control compatibility with compile command @@ -55,27 +56,27 @@ import java.util.Objects; public class TestCompilerDirectivesCompatibilityCommandOn extends TestCompilerDirectivesCompatibilityBase{ - public void testCompatibility(CommandExecutor executor) throws Exception { + public void testCompatibility(CommandExecutor executor, int comp_level) throws Exception { // Call all validation twice to catch error when overwriting a directive // Flag is default on - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); // load directives that turn it off executor.execute("Compiler.directives_add " + control_off); - expect(!WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); // remove and see that it is true again executor.execute("Compiler.directives_remove"); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); } } diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java index 37c8d2b0181..8ec1fc9ee4e 100644 --- a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java @@ -24,16 +24,17 @@ /* * @test TestCompilerDirectivesCompatibilityFlag * @bug 8137167 - * @library /testlibrary /test/lib + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @build sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions * -XX:+PrintAssembly -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityFlag * @summary Test compiler control compatibility with compile command */ @@ -54,28 +55,28 @@ import java.util.Objects; public class TestCompilerDirectivesCompatibilityFlag extends TestCompilerDirectivesCompatibilityBase { - public void testCompatibility(CommandExecutor executor) throws Exception { + public void testCompatibility(CommandExecutor executor, int comp_level) throws Exception { // Call all validation twice to catch error when overwriting a directive // Flag is default on expect(WB.getBooleanVMFlag("PrintAssembly")); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); // load directives that turn it off executor.execute("Compiler.directives_add " + control_off); - expect(!WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); // remove and see that it is true again executor.execute("Compiler.directives_remove"); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); } } From 607365df56d16257ed9df05ad3a8a72cfe4cba53 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Thu, 25 Feb 2016 10:44:19 +0100 Subject: [PATCH 034/183] 8149789: SIGSEGV in CompileTask::print Print tasks from active compile threads requires safepoint Reviewed-by: kvn --- hotspot/src/share/vm/compiler/compileBroker.cpp | 1 - hotspot/src/share/vm/runtime/vm_operations.cpp | 4 ++++ hotspot/src/share/vm/runtime/vm_operations.hpp | 12 ++++++++++++ hotspot/src/share/vm/services/diagnosticCommand.cpp | 3 ++- 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 44903801d83..8689088455c 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -469,7 +469,6 @@ CompileQueue* CompileBroker::compile_queue(int comp_level) { void CompileBroker::print_compile_queues(outputStream* st) { st->print_cr("Current compiles: "); MutexLocker locker(MethodCompileQueue_lock); - MutexLocker locker2(Threads_lock); char buf[2000]; int buflen = sizeof(buf); diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp index 80def983a56..db7341d869f 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.cpp +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp @@ -485,6 +485,10 @@ void VM_Exit::wait_if_vm_exited() { } } +void VM_PrintCompileQueue::doit() { + CompileBroker::print_compile_queues(_out); +} + #if INCLUDE_SERVICES void VM_PrintClassHierarchy::doit() { KlassHierarchy::print_class_hierarchy(_out, _print_interfaces, _print_subclasses, _classname); diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index 03392091aee..a5b0ddbf47b 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -105,6 +105,7 @@ template(DumpHashtable) \ template(DumpTouchedMethods) \ template(MarkActiveNMethods) \ + template(PrintCompileQueue) \ template(PrintClassHierarchy) \ class VM_Operation: public CHeapObj { @@ -421,6 +422,17 @@ class VM_Exit: public VM_Operation { void doit(); }; +class VM_PrintCompileQueue: public VM_Operation { + private: + outputStream* _out; + + public: + VM_PrintCompileQueue(outputStream* st) : _out(st) {} + VMOp_Type type() const { return VMOp_PrintCompileQueue; } + Mode evaluation_mode() const { return _safepoint; } + void doit(); +}; + #if INCLUDE_SERVICES class VM_PrintClassHierarchy: public VM_Operation { private: diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index d6dde5eef83..c634edfce73 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -832,7 +832,8 @@ void VMDynamicLibrariesDCmd::execute(DCmdSource source, TRAPS) { } void CompileQueueDCmd::execute(DCmdSource source, TRAPS) { - CompileBroker::print_compile_queues(output()); + VM_PrintCompileQueue printCompileQueueOp(output()); + VMThread::execute(&printCompileQueueOp); } void CodeListDCmd::execute(DCmdSource source, TRAPS) { From d596cf06af037f78f9099876d7558ba2f7bb0252 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Thu, 25 Feb 2016 10:44:51 +0100 Subject: [PATCH 035/183] 8069160: serviceability/dcmd/compiler/CompilerQueueTest.java fails due to class not found Use whitebox to test specific cases making test less fragile Reviewed-by: kvn --- .../dcmd/compiler/CompilerQueueTest.java | 155 ++++++++++++------ 1 file changed, 108 insertions(+), 47 deletions(-) diff --git a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java index fac5034f984..321be8257f5 100644 --- a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java +++ b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java @@ -24,25 +24,33 @@ /* * @test CompilerQueueTest * @bug 8054889 - * @library /testlibrary + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * jdk.jvmstat/sun.jvmstat.monitor - * @ignore 8069160 * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @run testng CompilerQueueTest - * @run testng/othervm -XX:-TieredCompilation CompilerQueueTest - * @run testng/othervm -Xint CompilerQueueTest + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -Xmixed -XX:+WhiteBoxAPI CompilerQueueTest + * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -Xmixed -XX:-TieredCompilation -XX:+WhiteBoxAPI CompilerQueueTest + * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -Xint -XX:+WhiteBoxAPI CompilerQueueTest * @summary Test of diagnostic command Compiler.queue */ +import compiler.testlibrary.CompilerUtils; import jdk.test.lib.OutputAnalyzer; import jdk.test.lib.dcmd.CommandExecutor; import jdk.test.lib.dcmd.JMXExecutor; import org.testng.annotations.Test; +import org.testng.Assert; +import sun.hotspot.WhiteBox; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; import java.util.Iterator; public class CompilerQueueTest { @@ -54,70 +62,123 @@ public class CompilerQueueTest { * * Output example: * - * Contents of C1 compile queue - * ---------------------------- - * 73 3 java.lang.AbstractStringBuilder::append (50 bytes) - * 74 1 java.util.TreeMap::size (5 bytes) - * 75 3 java.lang.StringBuilder::append (8 bytes) - * 83 3 java.util.TreeMap$ValueIterator::next (8 bytes) - * 84 1 javax.management.MBeanFeatureInfo::getName (5 bytes) - * ---------------------------- - * Contents of C2 compile queue - * ---------------------------- + * Current compiles: + * C1 CompilerThread14 267 3 java.net.URLStreamHandler::parseURL (1166 bytes) + * C1 CompilerThread13 760 3 javax.management.StandardMBean::getDescription (11 bytes) + * C1 CompilerThread12 757 s 3 com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory::getMapping (27 bytes) + * C1 CompilerThread11 756 s! 3 com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory::mappingForType (110 bytes) + * C1 CompilerThread10 761 3 java.lang.StringLatin1::indexOf (121 bytes) + * C2 CompilerThread7 769 4 CompilerQueueTest::testcaseMethod4 (1 bytes) + * + * C1 compile queue: + * 762 3 java.lang.invoke.MethodType::basicType (8 bytes) + * 763 3 java.util.ArrayList::rangeCheck (22 bytes) + * 764 3 java.util.ArrayList::elementData (7 bytes) + * 765 3 jdk.internal.org.objectweb.asm.MethodVisitor:: (35 bytes) + * 766 1 CompilerQueueTest::testcaseMethod1 (1 bytes) + * 767 2 CompilerQueueTest::testcaseMethod2 (1 bytes) + * 768 3 CompilerQueueTest::testcaseMethod3 (1 bytes) + * 770 3 java.util.Properties::getProperty (46 bytes) + * + * C2 compile queue: * Empty - * ---------------------------- * **/ + protected static final WhiteBox WB = WhiteBox.getWhiteBox(); + public void run(CommandExecutor executor) { + TestCase[] testcases = { + new TestCase(1, "testcaseMethod1"), + new TestCase(2, "testcaseMethod2"), + new TestCase(3, "testcaseMethod3"), + new TestCase(4, "testcaseMethod4"), + }; + + // Lock compilation makes all compiles stay in queue or compile thread before completion + WB.lockCompilation(); + + // Enqueue one test method for each available level + int[] complevels = CompilerUtils.getAvailableCompilationLevels(); + for (int level : complevels) { + TestCase testcase = testcases[level - 1]; + + boolean added = WB.enqueueMethodForCompilation(testcase.method, testcase.level); + // Set results to false for those methods we must to find + // We will also assert if we find any test method we don't expect + Assert.assertTrue(WB.isMethodQueuedForCompilation(testcase.method)); + testcase.check = false; + } + // Get output from dcmd (diagnostic command) OutputAnalyzer output = executor.execute("Compiler.queue"); Iterator lines = output.asLines().iterator(); + // Loop over output set result for all found methods while (lines.hasNext()) { String str = lines.next(); - if (str.startsWith("Contents of C")) { - match(lines.next(), "----------------------------"); - str = lines.next(); - if (!str.equals("Empty")) { - while (str.charAt(0) != '-') { - validateMethodLine(str); - str = lines.next(); + // Fast check for common part of method name + if (str.contains("testcaseMethod")) { + for (TestCase testcase : testcases) { + if (str.contains(testcase.methodName)) { + Assert.assertFalse(testcase.check, "Must not be found or already found."); + testcase.check = true; } - } else { - str = lines.next(); } - match(str,"----------------------------"); - } else { - Assert.fail("Failed parsing dcmd queue, line: " + str); } } - } - private static void validateMethodLine(String str) { - // Skip until package/class name begins. Trim to remove whitespace that - // may differ. - String name = str.substring(14).trim(); - int sep = name.indexOf("::"); - if (sep == -1) { - Assert.fail("Failed dcmd queue, didn't find separator :: in: " + name); + for (TestCase testcase : testcases) { + if (!testcase.check) { + // If this method wasn't found it must have been removed by policy, + // verify that it is now removed from the queue + Assert.assertFalse(WB.isMethodQueuedForCompilation(testcase.method), "Must be found or not in queue"); + } + // Otherwise all good. } - try { - Class.forName(name.substring(0, sep)); - } catch (ClassNotFoundException e) { - Assert.fail("Failed dcmd queue, Class for name: " + str); - } - } - public static void match(String line, String str) { - if (!line.equals(str)) { - Assert.fail("String equals: " + line + ", " + str); - } + // Enable compilations again + WB.unlockCompilation(); } @Test public void jmx() { run(new JMXExecutor()); } + + public void testcaseMethod1() { + } + + public void testcaseMethod2() { + } + + public void testcaseMethod3() { + } + + public void testcaseMethod4() { + } + + public static Method getMethod(Class klass, String name, Class... parameterTypes) { + try { + return klass.getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException("exception on getting method Helper." + name, e); + } + } + + class TestCase { + Method method; + int level; + String methodName; + Boolean check; + + public TestCase(int level, String methodName) { + this.method = getMethod(CompilerQueueTest.class, methodName); + this.level = level; + this.methodName = methodName; + this.check = true; + } + } + } From 4a8c4fc0740251d8f753ee97c6bc2aaae2965eef Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 25 Feb 2016 15:10:16 +0300 Subject: [PATCH 036/183] 8150534: C1 compilation fails with "Constant field loads are folded during parsing" Reviewed-by: vlivanov, thartmann --- hotspot/src/share/vm/c1/c1_Canonicalizer.cpp | 16 ++++++++++------ .../compiler/c1/CanonicalizeArrayLength.java | 7 ++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp index f6e5baa0c28..033beb0d25e 100644 --- a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp +++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp @@ -224,6 +224,7 @@ void Canonicalizer::do_StoreField (StoreField* x) { void Canonicalizer::do_ArrayLength (ArrayLength* x) { NewArray* na; Constant* ct; + LoadField* lf; if ((na = x->array()->as_NewArray()) != NULL) { // New arrays might have the known length. @@ -244,12 +245,15 @@ void Canonicalizer::do_ArrayLength (ArrayLength* x) { set_constant(cnst->value()->length()); } -#ifdef ASSERT - } else { - LoadField* lf = x->array()->as_LoadField(); - bool is_static_constant = (lf != NULL) && lf->field()->is_constant() && lf->field()->is_static(); - assert(!is_static_constant, "Constant field loads are folded during parsing"); -#endif // ASSERT + } else if ((lf = x->array()->as_LoadField()) != NULL) { + ciField* field = lf->field(); + if (field->is_constant() && field->is_static()) { + assert(PatchALot || ScavengeRootsInCode < 2, "Constant field loads are folded during parsing"); + ciObject* c = field->constant_value().as_object(); + if (!c->is_null_object()) { + set_constant(c->as_array()->length()); + } + } } } diff --git a/hotspot/test/compiler/c1/CanonicalizeArrayLength.java b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java index f8de9e595c9..9971d25bde8 100644 --- a/hotspot/test/compiler/c1/CanonicalizeArrayLength.java +++ b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java @@ -23,12 +23,13 @@ /* * @test - * @bug 8150102 8150514 + * @bug 8150102 8150514 8150534 * @summary C1 crashes in Canonicalizer::do_ArrayLength() after fix for JDK-8150102 * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation CanonicalizeArrayLength - * + * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:+PatchALot CanonicalizeArrayLength + * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:ScavengeRootsInCode=0 CanonicalizeArrayLength + * @run main/othervm -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:ScavengeRootsInCode=1 CanonicalizeArrayLength */ - public class CanonicalizeArrayLength { int[] arr = new int[42]; int[] arrNull = null; From 88575c5de777893560d39060bc5e65725b2f1487 Mon Sep 17 00:00:00 2001 From: Christian Thalinger Date: Wed, 24 Feb 2016 09:22:45 -0800 Subject: [PATCH 037/183] 8150561: [AArch64] JVMCI improvements Reviewed-by: kvn --- hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp | 2 +- hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp | 7 +++++++ .../src/jdk/vm/ci/hotspot/HotSpotVMConfig.java | 7 ++----- hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp | 8 ++++++++ hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp | 8 ++++++++ hotspot/src/share/vm/runtime/frame.cpp | 4 ++-- 6 files changed, 28 insertions(+), 8 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp index 3e65f538de5..b302548557b 100644 --- a/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp @@ -74,7 +74,7 @@ void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, T void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS) { address pc = _instructions->start() + pc_offset; NativeInstruction* inst = nativeInstruction_at(pc); - if (inst->is_adr_aligned()) { + if (inst->is_adr_aligned() || inst->is_ldr_literal()) { address dest = _constants->start() + data_offset; _instructions->relocate(pc, section_word_Relocation::spec((address) dest, CodeBuffer::SECT_CONSTS)); TRACE_jvmci_3("relocating at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset); diff --git a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp index 72c3479659c..d83017c1770 100644 --- a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp @@ -105,13 +105,20 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { inline friend NativeInstruction* nativeInstruction_at(address address); static bool is_adrp_at(address instr); + static bool is_ldr_literal_at(address instr); + + bool is_ldr_literal() { + return is_ldr_literal_at(addr_at(0)); + } + static bool is_ldrw_to_zr(address instr); static bool is_call_at(address instr) { const uint32_t insn = (*(uint32_t*)instr); return (insn >> 26) == 0b100101; } + bool is_call() { return is_call_at(addr_at(0)); } diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 3e90a4d73b0..88da9e5b32a 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -1141,7 +1141,7 @@ public class HotSpotVMConfig { @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_sp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET) @Stable private int javaFrameAnchorLastJavaSpOffset; @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_pc", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable private int javaFrameAnchorLastJavaPcOffset; - @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_fp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET, archs = {"amd64"}) @Stable private int javaFrameAnchorLastJavaFpOffset; + @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_fp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET, archs = {"aarch64, amd64"}) @Stable private int javaFrameAnchorLastJavaFpOffset; @HotSpotVMField(name = "JavaFrameAnchor::_flags", type = "int", get = HotSpotVMField.Type.OFFSET, archs = {"sparc"}) @Stable private int javaFrameAnchorFlagsOffset; public int threadLastJavaSpOffset() { @@ -1152,11 +1152,8 @@ public class HotSpotVMConfig { return javaThreadAnchorOffset + javaFrameAnchorLastJavaPcOffset; } - /** - * This value is only valid on AMD64. - */ public int threadLastJavaFpOffset() { - // TODO add an assert for AMD64 + assert getHostArchitectureName().equals("aarch64") || getHostArchitectureName().equals("amd64"); return javaThreadAnchorOffset + javaFrameAnchorLastJavaFpOffset; } diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp index cb06c34d4b6..2043b59d5e1 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp @@ -551,6 +551,14 @@ JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Hand compiler, _debug_recorder, _dependencies, env, id, has_unsafe_access, _has_wide_vector, installed_code, compiled_code, speculation_log); cb = nm; + if (nm != NULL && env == NULL) { + DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, compiler); + bool printnmethods = directive->PrintAssemblyOption || directive->PrintNMethodsOption; + if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) { + nm->print_nmethod(printnmethods); + } + DirectivesStack::release(directive); + } } if (cb != NULL) { diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp index 9456f34a0eb..99a7fbd3ac9 100644 --- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp @@ -592,6 +592,14 @@ #endif // TARGET_OS_FAMILY_bsd +#ifdef TARGET_ARCH_aarch64 + +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) + +#endif // TARGET_ARCH_aarch64 + + #ifdef TARGET_ARCH_x86 #define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp index 3abf884cfbb..1a72cec46a8 100644 --- a/hotspot/src/share/vm/runtime/frame.cpp +++ b/hotspot/src/share/vm/runtime/frame.cpp @@ -662,14 +662,14 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose st->print("J %d%s %s ", nm->compile_id(), (nm->is_osr_method() ? "%" : ""), ((nm->compiler() != NULL) ? nm->compiler()->name() : "")); + st->print("%s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+" INTPTR_FORMAT "]", + buf, m->code_size(), p2i(_pc), p2i(_cb->code_begin()), _pc - _cb->code_begin()); #if INCLUDE_JVMCI char* jvmciName = nm->jvmci_installed_code_name(buf, buflen); if (jvmciName != NULL) { st->print(" (%s)", jvmciName); } #endif - st->print("%s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+" INTPTR_FORMAT "]", - buf, m->code_size(), p2i(_pc), p2i(_cb->code_begin()), _pc - _cb->code_begin()); } else { st->print("J " PTR_FORMAT, p2i(pc())); } From abebc2da5c26b42098d9bd95d9a7d790916183ab Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 26 Feb 2016 01:58:26 +0300 Subject: [PATCH 038/183] 8150186: Folding mismatched accesses with @Stable is incorrect Reviewed-by: kvn, jrose, shade --- hotspot/src/share/vm/ci/ciArray.cpp | 3 +- hotspot/src/share/vm/opto/memnode.cpp | 14 +++- .../unsafe/UnsafeGetStableArrayElement.java | 68 +++++++++++++++++++ 3 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java diff --git a/hotspot/src/share/vm/ci/ciArray.cpp b/hotspot/src/share/vm/ci/ciArray.cpp index f527d3ed538..04a6db8df3f 100644 --- a/hotspot/src/share/vm/ci/ciArray.cpp +++ b/hotspot/src/share/vm/ci/ciArray.cpp @@ -107,8 +107,9 @@ ciConstant ciArray::element_value_by_offset(intptr_t element_offset) { intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt); intptr_t index = (element_offset - header) >> shift; intptr_t offset = header + ((intptr_t)index << shift); - if (offset != element_offset || index != (jint)index) + if (offset != element_offset || index != (jint)index || index < 0 || index >= length()) { return ciConstant(); + } return element_value((jint) index); } diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 75a699349f8..55ca4581485 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -1582,6 +1582,15 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls, return NULL; } +static bool is_mismatched_access(ciConstant con, BasicType loadbt) { + BasicType conbt = con.basic_type(); + assert(conbt != T_NARROWOOP, "sanity"); + if (loadbt == T_NARROWOOP || loadbt == T_ARRAY) { + loadbt = T_OBJECT; + } + return (conbt != loadbt); +} + // Try to constant-fold a stable array element. static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) { assert(ary->const_oop(), "array should be constant"); @@ -1590,8 +1599,7 @@ static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicTyp // Decode the results of GraphKit::array_element_address. ciArray* aobj = ary->const_oop()->as_array(); ciConstant con = aobj->element_value_by_offset(off); - - if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) { + if (con.basic_type() != T_ILLEGAL && !is_mismatched_access(con, loadbt) && !con.is_null_or_zero()) { const Type* con_type = Type::make_from_constant(con); if (con_type != NULL) { if (con_type->isa_aryptr()) { @@ -1642,7 +1650,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { const bool off_beyond_header = ((uint)off >= (uint)min_base_off); // Try to constant-fold a stable array element. - if (FoldStableValues && ary->is_stable() && ary->const_oop() != NULL) { + if (FoldStableValues && !is_mismatched_access() && ary->is_stable() && ary->const_oop() != NULL) { // Make sure the reference is not into the header and the offset is constant if (off_beyond_header && adr->is_AddP() && off != Type::OffsetBot) { const Type* con_type = fold_stable_ary_elem(ary, off, memory_type()); diff --git a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java new file mode 100644 index 00000000000..afdb1a6e7a3 --- /dev/null +++ b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016, 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. + */ + +/* + * @test + * @summary tests on constant folding of unsafe get operations + * @library /testlibrary /test/lib + * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions + * -Xbatch -XX:-TieredCompilation + * -XX:+FoldStableValues + * UnsafeGetStableArrayElement + * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions + * -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+FoldStableValues + * UnsafeGetStableArrayElement + */ +import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.Stable; +import java.util.concurrent.Callable; + +import static jdk.internal.misc.Unsafe.*; +import static jdk.test.lib.Asserts.*; + +public class UnsafeGetStableArrayElement { + @Stable static final byte[] STABLE_BYTE_ARRAY = new byte[] { 0, 1, -128, 127}; + + static final Unsafe U = Unsafe.getUnsafe(); + + static int testChar() { + return U.getChar(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET + 0 * ARRAY_CHAR_INDEX_SCALE) + + U.getChar(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET + 1 * ARRAY_CHAR_INDEX_SCALE); + } + + static void run(Callable c) throws Exception { + Object first = c.call(); + for (int i = 0; i < 20_000; i++) { + assertEQ(first, c.call()); + } + } + + public static void main(String[] args) throws Exception { + run(UnsafeGetStableArrayElement::testChar); + } +} From a7d78599d772bff1a3b24c179370a55bec9a1f63 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 26 Feb 2016 01:58:29 +0300 Subject: [PATCH 039/183] 8150436: Incorrect invocation mode when linkToInteface linker is eliminated Reviewed-by: kvn, shade --- .../src/share/vm/runtime/sharedRuntime.cpp | 19 +++++++++++++------ .../jsr292/NonInlinedCall/InvokeTest.java | 5 ++++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index 5b862a01fab..4adec0c45ca 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -1134,12 +1134,19 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread, MethodHandles::is_signature_polymorphic_intrinsic(id)) { bc = MethodHandles::signature_polymorphic_intrinsic_bytecode(id); - // Need to adjust invokehandle since inlining through signature-polymorphic - // method happened. - if (bc == Bytecodes::_invokehandle && - !MethodHandles::is_signature_polymorphic_method(attached_method())) { - bc = attached_method->is_static() ? Bytecodes::_invokestatic - : Bytecodes::_invokevirtual; + // Adjust invocation mode according to the attached method. + switch (bc) { + case Bytecodes::_invokeinterface: + if (!attached_method->method_holder()->is_interface()) { + bc = Bytecodes::_invokevirtual; + } + break; + case Bytecodes::_invokehandle: + if (!MethodHandles::is_signature_polymorphic_method(attached_method())) { + bc = attached_method->is_static() ? Bytecodes::_invokestatic + : Bytecodes::_invokevirtual; + } + break; } } } else { diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java index 02bdef91a10..90724b371a8 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java @@ -180,7 +180,10 @@ public class InvokeTest { static void testInterface() { System.out.println("linkToInterface"); - // Monomorphic case (optimized virtual call) + // Monomorphic case (optimized virtual call), concrete target method + run(() -> linkToInterface(new P1(), P1.class)); + + // Monomorphic case (optimized virtual call), default target method run(() -> linkToInterface(new T(), I.class)); // Megamorphic case (virtual call) From 782e6b33f2d63d73b14021f46fb36fdc218abed5 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 26 Feb 2016 15:54:55 +0300 Subject: [PATCH 040/183] 8068038: C2: large constant offsets aren't handled on SPARC Reviewed-by: kvn --- hotspot/src/cpu/sparc/vm/sparc.ad | 368 ++++++++++++++---------------- 1 file changed, 175 insertions(+), 193 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 6bbef4e5708..5cf884a5501 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -948,28 +948,28 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, PhaseRegAlloc* ra, const MachNode* n, } #endif - uint instr; - instr = (Assembler::ldst_op << 30) - | (dst_enc << 25) - | (primary << 19) - | (src1_enc << 14); + uint instr = (Assembler::ldst_op << 30) + | (dst_enc << 25) + | (primary << 19) + | (src1_enc << 14); uint index = src2_enc; int disp = disp32; if (src1_enc == R_SP_enc || src1_enc == R_FP_enc) { disp += STACK_BIAS; - // Quick fix for JDK-8029668: check that stack offset fits, bailout if not + // Check that stack offset fits, load into O7 if not if (!Assembler::is_simm13(disp)) { - ra->C->record_method_not_compilable("unable to handle large constant offsets"); - return; + MacroAssembler _masm(&cbuf); + __ set(disp, O7); + if (index != R_G0_enc) { + __ add(O7, reg_to_register_object(index), O7); + } + index = R_O7_enc; + disp = 0; } } - // We should have a compiler bailout here rather than a guarantee. - // Better yet would be some mechanism to handle variable-size matches correctly. - guarantee(Assembler::is_simm13(disp), "Do not match large constant offsets" ); - if( disp == 0 ) { // use reg-reg form // bit 13 is already zero @@ -983,7 +983,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, PhaseRegAlloc* ra, const MachNode* n, cbuf.insts()->emit_int32(instr); #ifdef ASSERT - { + if (VerifyOops) { MacroAssembler _masm(&cbuf); if (is_verified_oop_base) { __ verify_oop(reg_to_register_object(src1_enc)); @@ -1342,7 +1342,7 @@ int MachEpilogNode::safepoint_offset() const { // Figure out which register class each belongs in: rc_int, rc_float, rc_stack enum RC { rc_bad, rc_int, rc_float, rc_stack }; static enum RC rc_class( OptoReg::Name reg ) { - if( !OptoReg::is_valid(reg) ) return rc_bad; + if (!OptoReg::is_valid(reg)) return rc_bad; if (OptoReg::is_stack(reg)) return rc_stack; VMReg r = OptoReg::as_VMReg(reg); if (r->is_Register()) return rc_int; @@ -1350,66 +1350,79 @@ static enum RC rc_class( OptoReg::Name reg ) { return rc_float; } -static int impl_helper(const MachNode* mach, CodeBuffer* cbuf, PhaseRegAlloc* ra, bool do_size, bool is_load, int offset, int reg, int opcode, const char *op_str, int size, outputStream* st ) { +#ifndef PRODUCT +ATTRIBUTE_PRINTF(2, 3) +static void print_helper(outputStream* st, const char* format, ...) { + if (st->position() > 0) { + st->cr(); + st->sp(); + } + va_list ap; + va_start(ap, format); + st->vprint(format, ap); + va_end(ap); +} +#endif // !PRODUCT + +static void impl_helper(const MachNode* mach, CodeBuffer* cbuf, PhaseRegAlloc* ra, bool is_load, int offset, int reg, int opcode, const char *op_str, outputStream* st) { if (cbuf) { emit_form3_mem_reg(*cbuf, ra, mach, opcode, -1, R_SP_enc, offset, 0, Matcher::_regEncode[reg]); } #ifndef PRODUCT - else if (!do_size) { - if (size != 0) st->print("\n\t"); - if (is_load) st->print("%s [R_SP + #%d],R_%s\t! spill",op_str,offset,OptoReg::regname(reg)); - else st->print("%s R_%s,[R_SP + #%d]\t! spill",op_str,OptoReg::regname(reg),offset); + else { + if (is_load) { + print_helper(st, "%s [R_SP + #%d],R_%s\t! spill", op_str, offset, OptoReg::regname(reg)); + } else { + print_helper(st, "%s R_%s,[R_SP + #%d]\t! spill", op_str, OptoReg::regname(reg), offset); + } } #endif - return size+4; } -static int impl_mov_helper( CodeBuffer *cbuf, bool do_size, int src, int dst, int op1, int op2, const char *op_str, int size, outputStream* st ) { - if( cbuf ) emit3( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst], op1, 0, op2, Matcher::_regEncode[src] ); +static void impl_mov_helper(CodeBuffer *cbuf, int src, int dst, int op1, int op2, const char *op_str, outputStream* st) { + if (cbuf) { + emit3(*cbuf, Assembler::arith_op, Matcher::_regEncode[dst], op1, 0, op2, Matcher::_regEncode[src]); + } #ifndef PRODUCT - else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); - st->print("%s R_%s,R_%s\t! spill",op_str,OptoReg::regname(src),OptoReg::regname(dst)); + else { + print_helper(st, "%s R_%s,R_%s\t! spill", op_str, OptoReg::regname(src), OptoReg::regname(dst)); } #endif - return size+4; } -uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, - PhaseRegAlloc *ra_, - bool do_size, - outputStream* st ) const { +static void mach_spill_copy_implementation_helper(const MachNode* mach, + CodeBuffer *cbuf, + PhaseRegAlloc *ra_, + outputStream* st) { // Get registers to move - OptoReg::Name src_second = ra_->get_reg_second(in(1)); - OptoReg::Name src_first = ra_->get_reg_first(in(1)); - OptoReg::Name dst_second = ra_->get_reg_second(this ); - OptoReg::Name dst_first = ra_->get_reg_first(this ); + OptoReg::Name src_second = ra_->get_reg_second(mach->in(1)); + OptoReg::Name src_first = ra_->get_reg_first(mach->in(1)); + OptoReg::Name dst_second = ra_->get_reg_second(mach); + OptoReg::Name dst_first = ra_->get_reg_first(mach); enum RC src_second_rc = rc_class(src_second); - enum RC src_first_rc = rc_class(src_first); + enum RC src_first_rc = rc_class(src_first); enum RC dst_second_rc = rc_class(dst_second); - enum RC dst_first_rc = rc_class(dst_first); + enum RC dst_first_rc = rc_class(dst_first); - assert( OptoReg::is_valid(src_first) && OptoReg::is_valid(dst_first), "must move at least 1 register" ); + assert(OptoReg::is_valid(src_first) && OptoReg::is_valid(dst_first), "must move at least 1 register"); - // Generate spill code! - int size = 0; - - if( src_first == dst_first && src_second == dst_second ) - return size; // Self copy, no move + if (src_first == dst_first && src_second == dst_second) { + return; // Self copy, no move + } // -------------------------------------- // Check for mem-mem move. Load into unused float registers and fall into // the float-store case. - if( src_first_rc == rc_stack && dst_first_rc == rc_stack ) { + if (src_first_rc == rc_stack && dst_first_rc == rc_stack) { int offset = ra_->reg2offset(src_first); // Further check for aligned-adjacent pair, so we can use a double load - if( (src_first&1)==0 && src_first+1 == src_second ) { + if ((src_first&1) == 0 && src_first+1 == src_second) { src_second = OptoReg::Name(R_F31_num); src_second_rc = rc_float; - size = impl_helper(this,cbuf,ra_,do_size,true,offset,R_F30_num,Assembler::lddf_op3,"LDDF",size, st); + impl_helper(mach, cbuf, ra_, true, offset, R_F30_num, Assembler::lddf_op3, "LDDF", st); } else { - size = impl_helper(this,cbuf,ra_,do_size,true,offset,R_F30_num,Assembler::ldf_op3 ,"LDF ",size, st); + impl_helper(mach, cbuf, ra_, true, offset, R_F30_num, Assembler::ldf_op3, "LDF ", st); } src_first = OptoReg::Name(R_F30_num); src_first_rc = rc_float; @@ -1417,7 +1430,7 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, if( src_second_rc == rc_stack && dst_second_rc == rc_stack ) { int offset = ra_->reg2offset(src_second); - size = impl_helper(this,cbuf,ra_,do_size,true,offset,R_F31_num,Assembler::ldf_op3,"LDF ",size, st); + impl_helper(mach, cbuf, ra_, true, offset, R_F31_num, Assembler::ldf_op3, "LDF ", st); src_second = OptoReg::Name(R_F31_num); src_second_rc = rc_float; } @@ -1427,36 +1440,38 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS < 3) { int offset = frame::register_save_words*wordSize; if (cbuf) { - emit3_simm13( *cbuf, Assembler::arith_op, R_SP_enc, Assembler::sub_op3, R_SP_enc, 16 ); - impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stf_op3 ,"STF ",size, st); - impl_helper(this,cbuf,ra_,do_size,true ,offset,dst_first,Assembler::lduw_op3,"LDUW",size, st); - emit3_simm13( *cbuf, Assembler::arith_op, R_SP_enc, Assembler::add_op3, R_SP_enc, 16 ); + emit3_simm13(*cbuf, Assembler::arith_op, R_SP_enc, Assembler::sub_op3, R_SP_enc, 16); + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st); + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st); + emit3_simm13(*cbuf, Assembler::arith_op, R_SP_enc, Assembler::add_op3, R_SP_enc, 16); } #ifndef PRODUCT - else if (!do_size) { - if (size != 0) st->print("\n\t"); - st->print( "SUB R_SP,16,R_SP\n"); - impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stf_op3 ,"STF ",size, st); - impl_helper(this,cbuf,ra_,do_size,true ,offset,dst_first,Assembler::lduw_op3,"LDUW",size, st); - st->print("\tADD R_SP,16,R_SP\n"); + else { + print_helper(st, "SUB R_SP,16,R_SP"); + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st); + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st); + print_helper(st, "ADD R_SP,16,R_SP"); } #endif - size += 16; } // Check for float->int copy on T4 if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS >= 3) { // Further check for aligned-adjacent pair, so we can use a double move - if ((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second) - return impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mdtox_opf,"MOVDTOX",size, st); - size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mstouw_opf,"MOVSTOUW",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mdtox_opf, "MOVDTOX", st); + return; + } + impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mstouw_opf, "MOVSTOUW", st); } // Check for int->float copy on T4 if (src_first_rc == rc_int && dst_first_rc == rc_float && UseVIS >= 3) { // Further check for aligned-adjacent pair, so we can use a double move - if ((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second) - return impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mxtod_opf,"MOVXTOD",size, st); - size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mwtos_opf,"MOVWTOS",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mxtod_opf, "MOVXTOD", st); + return; + } + impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mwtos_opf, "MOVWTOS", st); } // -------------------------------------- @@ -1466,10 +1481,10 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, // there. Misaligned sources only come from native-long-returns (handled // special below). #ifndef _LP64 - if( src_first_rc == rc_int && // source is already big-endian + if (src_first_rc == rc_int && // source is already big-endian src_second_rc != rc_bad && // 64-bit move - ((dst_first&1)!=0 || dst_second != dst_first+1) ) { // misaligned dst - assert( (src_first&1)==0 && src_second == src_first+1, "source must be aligned" ); + ((dst_first & 1) != 0 || dst_second != dst_first + 1)) { // misaligned dst + assert((src_first & 1) == 0 && src_second == src_first + 1, "source must be aligned"); // Do the big-endian flop. OptoReg::Name tmp = dst_first ; dst_first = dst_second ; dst_second = tmp ; enum RC tmp_rc = dst_first_rc; dst_first_rc = dst_second_rc; dst_second_rc = tmp_rc; @@ -1478,30 +1493,28 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, // -------------------------------------- // Check for integer reg-reg copy - if( src_first_rc == rc_int && dst_first_rc == rc_int ) { + if (src_first_rc == rc_int && dst_first_rc == rc_int) { #ifndef _LP64 - if( src_first == R_O0_num && src_second == R_O1_num ) { // Check for the evil O0/O1 native long-return case + if (src_first == R_O0_num && src_second == R_O1_num) { // Check for the evil O0/O1 native long-return case // Note: The _first and _second suffixes refer to the addresses of the the 2 halves of the 64-bit value // as stored in memory. On a big-endian machine like SPARC, this means that the _second // operand contains the least significant word of the 64-bit value and vice versa. OptoReg::Name tmp = OptoReg::Name(R_O7_num); - assert( (dst_first&1)==0 && dst_second == dst_first+1, "return a native O0/O1 long to an aligned-adjacent 64-bit reg" ); + assert((dst_first & 1) == 0 && dst_second == dst_first + 1, "return a native O0/O1 long to an aligned-adjacent 64-bit reg" ); // Shift O0 left in-place, zero-extend O1, then OR them into the dst - if( cbuf ) { - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[tmp], Assembler::sllx_op3, Matcher::_regEncode[src_first], 0x1020 ); - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[src_second], Assembler::srl_op3, Matcher::_regEncode[src_second], 0x0000 ); - emit3 ( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst_first], Assembler:: or_op3, Matcher::_regEncode[tmp], 0, Matcher::_regEncode[src_second] ); + if ( cbuf ) { + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[tmp], Assembler::sllx_op3, Matcher::_regEncode[src_first], 0x1020); + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[src_second], Assembler::srl_op3, Matcher::_regEncode[src_second], 0x0000); + emit3 (*cbuf, Assembler::arith_op, Matcher::_regEncode[dst_first], Assembler:: or_op3, Matcher::_regEncode[tmp], 0, Matcher::_regEncode[src_second]); #ifndef PRODUCT - } else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); - st->print("SLLX R_%s,32,R_%s\t! Move O0-first to O7-high\n\t", OptoReg::regname(src_first), OptoReg::regname(tmp)); - st->print("SRL R_%s, 0,R_%s\t! Zero-extend O1\n\t", OptoReg::regname(src_second), OptoReg::regname(src_second)); - st->print("OR R_%s,R_%s,R_%s\t! spill",OptoReg::regname(tmp), OptoReg::regname(src_second), OptoReg::regname(dst_first)); + } else { + print_helper(st, "SLLX R_%s,32,R_%s\t! Move O0-first to O7-high\n\t", OptoReg::regname(src_first), OptoReg::regname(tmp)); + print_helper(st, "SRL R_%s, 0,R_%s\t! Zero-extend O1\n\t", OptoReg::regname(src_second), OptoReg::regname(src_second)); + print_helper(st, "OR R_%s,R_%s,R_%s\t! spill",OptoReg::regname(tmp), OptoReg::regname(src_second), OptoReg::regname(dst_first)); #endif } - return size+12; - } - else if( dst_first == R_I0_num && dst_second == R_I1_num ) { + return; + } else if (dst_first == R_I0_num && dst_second == R_I1_num) { // returning a long value in I0/I1 // a SpillCopy must be able to target a return instruction's reg_class // Note: The _first and _second suffixes refer to the addresses of the the 2 halves of the 64-bit value @@ -1511,27 +1524,25 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, if (src_first == dst_first) { tdest = OptoReg::Name(R_O7_num); - size += 4; } - if( cbuf ) { - assert( (src_first&1) == 0 && (src_first+1) == src_second, "return value was in an aligned-adjacent 64-bit reg"); + if (cbuf) { + assert((src_first & 1) == 0 && (src_first + 1) == src_second, "return value was in an aligned-adjacent 64-bit reg"); // Shift value in upper 32-bits of src to lower 32-bits of I0; move lower 32-bits to I1 // ShrL_reg_imm6 - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[tdest], Assembler::srlx_op3, Matcher::_regEncode[src_second], 32 | 0x1000 ); + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[tdest], Assembler::srlx_op3, Matcher::_regEncode[src_second], 32 | 0x1000); // ShrR_reg_imm6 src, 0, dst - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst_second], Assembler::srl_op3, Matcher::_regEncode[src_first], 0x0000 ); + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[dst_second], Assembler::srl_op3, Matcher::_regEncode[src_first], 0x0000); if (tdest != dst_first) { - emit3 ( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst_first], Assembler::or_op3, 0/*G0*/, 0/*op2*/, Matcher::_regEncode[tdest] ); + emit3 (*cbuf, Assembler::arith_op, Matcher::_regEncode[dst_first], Assembler::or_op3, 0/*G0*/, 0/*op2*/, Matcher::_regEncode[tdest]); } } #ifndef PRODUCT - else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); // %%%%% !!!!! - st->print("SRLX R_%s,32,R_%s\t! Extract MSW\n\t",OptoReg::regname(src_second),OptoReg::regname(tdest)); - st->print("SRL R_%s, 0,R_%s\t! Extract LSW\n\t",OptoReg::regname(src_first),OptoReg::regname(dst_second)); + else { + print_helper(st, "SRLX R_%s,32,R_%s\t! Extract MSW\n\t",OptoReg::regname(src_second),OptoReg::regname(tdest)); + print_helper(st, "SRL R_%s, 0,R_%s\t! Extract LSW\n\t",OptoReg::regname(src_first),OptoReg::regname(dst_second)); if (tdest != dst_first) { - st->print("MOV R_%s,R_%s\t! spill\n\t", OptoReg::regname(tdest), OptoReg::regname(dst_first)); + print_helper(st, "MOV R_%s,R_%s\t! spill\n\t", OptoReg::regname(tdest), OptoReg::regname(dst_first)); } } #endif // PRODUCT @@ -1539,65 +1550,77 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, } #endif // !_LP64 // Else normal reg-reg copy - assert( src_second != dst_first, "smashed second before evacuating it" ); - size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::or_op3,0,"MOV ",size, st); - assert( (src_first&1) == 0 && (dst_first&1) == 0, "never move second-halves of int registers" ); + assert(src_second != dst_first, "smashed second before evacuating it"); + impl_mov_helper(cbuf, src_first, dst_first, Assembler::or_op3, 0, "MOV ", st); + assert((src_first & 1) == 0 && (dst_first & 1) == 0, "never move second-halves of int registers"); // This moves an aligned adjacent pair. // See if we are done. - if( src_first+1 == src_second && dst_first+1 == dst_second ) - return size; + if (src_first + 1 == src_second && dst_first + 1 == dst_second) { + return; + } } // Check for integer store - if( src_first_rc == rc_int && dst_first_rc == rc_stack ) { + if (src_first_rc == rc_int && dst_first_rc == rc_stack) { int offset = ra_->reg2offset(dst_first); // Further check for aligned-adjacent pair, so we can use a double store - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stx_op3,"STX ",size, st); - size = impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stw_op3,"STW ",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stx_op3, "STX ", st); + return; + } + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stw_op3, "STW ", st); } // Check for integer load - if( dst_first_rc == rc_int && src_first_rc == rc_stack ) { + if (dst_first_rc == rc_int && src_first_rc == rc_stack) { int offset = ra_->reg2offset(src_first); // Further check for aligned-adjacent pair, so we can use a double load - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_helper(this,cbuf,ra_,do_size,true,offset,dst_first,Assembler::ldx_op3 ,"LDX ",size, st); - size = impl_helper(this,cbuf,ra_,do_size,true,offset,dst_first,Assembler::lduw_op3,"LDUW",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::ldx_op3, "LDX ", st); + return; + } + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st); } // Check for float reg-reg copy - if( src_first_rc == rc_float && dst_first_rc == rc_float ) { + if (src_first_rc == rc_float && dst_first_rc == rc_float) { // Further check for aligned-adjacent pair, so we can use a double move - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::fpop1_op3,Assembler::fmovd_opf,"FMOVD",size, st); - size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::fpop1_op3,Assembler::fmovs_opf,"FMOVS",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_mov_helper(cbuf, src_first, dst_first, Assembler::fpop1_op3, Assembler::fmovd_opf, "FMOVD", st); + return; + } + impl_mov_helper(cbuf, src_first, dst_first, Assembler::fpop1_op3, Assembler::fmovs_opf, "FMOVS", st); } // Check for float store - if( src_first_rc == rc_float && dst_first_rc == rc_stack ) { + if (src_first_rc == rc_float && dst_first_rc == rc_stack) { int offset = ra_->reg2offset(dst_first); // Further check for aligned-adjacent pair, so we can use a double store - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stdf_op3,"STDF",size, st); - size = impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stf_op3 ,"STF ",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stdf_op3, "STDF", st); + return; + } + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st); } // Check for float load - if( dst_first_rc == rc_float && src_first_rc == rc_stack ) { + if (dst_first_rc == rc_float && src_first_rc == rc_stack) { int offset = ra_->reg2offset(src_first); // Further check for aligned-adjacent pair, so we can use a double load - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_helper(this,cbuf,ra_,do_size,true,offset,dst_first,Assembler::lddf_op3,"LDDF",size, st); - size = impl_helper(this,cbuf,ra_,do_size,true,offset,dst_first,Assembler::ldf_op3 ,"LDF ",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lddf_op3, "LDDF", st); + return; + } + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::ldf_op3, "LDF ", st); } // -------------------------------------------------------------------- // Check for hi bits still needing moving. Only happens for misaligned // arguments to native calls. - if( src_second == dst_second ) - return size; // Self copy; no move - assert( src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad" ); + if (src_second == dst_second) { + return; // Self copy; no move + } + assert(src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad"); #ifndef _LP64 // In the LP64 build, all registers can be moved as aligned/adjacent @@ -1609,52 +1632,57 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, // 32-bits of a 64-bit register, but are needed in low bits of another // register (else it's a hi-bits-to-hi-bits copy which should have // happened already as part of a 64-bit move) - if( src_second_rc == rc_int && dst_second_rc == rc_int ) { - assert( (src_second&1)==1, "its the evil O0/O1 native return case" ); - assert( (dst_second&1)==0, "should have moved with 1 64-bit move" ); + if (src_second_rc == rc_int && dst_second_rc == rc_int) { + assert((src_second & 1) == 1, "its the evil O0/O1 native return case"); + assert((dst_second & 1) == 0, "should have moved with 1 64-bit move"); // Shift src_second down to dst_second's low bits. - if( cbuf ) { - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst_second], Assembler::srlx_op3, Matcher::_regEncode[src_second-1], 0x1020 ); + if (cbuf) { + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[dst_second], Assembler::srlx_op3, Matcher::_regEncode[src_second-1], 0x1020); #ifndef PRODUCT - } else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); - st->print("SRLX R_%s,32,R_%s\t! spill: Move high bits down low",OptoReg::regname(src_second-1),OptoReg::regname(dst_second)); + } else { + print_helper(st, "SRLX R_%s,32,R_%s\t! spill: Move high bits down low", OptoReg::regname(src_second - 1), OptoReg::regname(dst_second)); #endif } - return size+4; + return; } // Check for high word integer store. Must down-shift the hi bits // into a temp register, then fall into the case of storing int bits. - if( src_second_rc == rc_int && dst_second_rc == rc_stack && (src_second&1)==1 ) { + if (src_second_rc == rc_int && dst_second_rc == rc_stack && (src_second & 1) == 1) { // Shift src_second down to dst_second's low bits. - if( cbuf ) { - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[R_O7_num], Assembler::srlx_op3, Matcher::_regEncode[src_second-1], 0x1020 ); + if (cbuf) { + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[R_O7_num], Assembler::srlx_op3, Matcher::_regEncode[src_second-1], 0x1020); #ifndef PRODUCT - } else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); - st->print("SRLX R_%s,32,R_%s\t! spill: Move high bits down low",OptoReg::regname(src_second-1),OptoReg::regname(R_O7_num)); + } else { + print_helper(st, "SRLX R_%s,32,R_%s\t! spill: Move high bits down low", OptoReg::regname(src_second-1), OptoReg::regname(R_O7_num)); #endif } - size+=4; src_second = OptoReg::Name(R_O7_num); // Not R_O7H_num! } // Check for high word integer load - if( dst_second_rc == rc_int && src_second_rc == rc_stack ) - return impl_helper(this,cbuf,ra_,do_size,true ,ra_->reg2offset(src_second),dst_second,Assembler::lduw_op3,"LDUW",size, st); + if (dst_second_rc == rc_int && src_second_rc == rc_stack) + return impl_helper(this, cbuf, ra_, true, ra_->reg2offset(src_second), dst_second, Assembler::lduw_op3, "LDUW", size, st); // Check for high word integer store - if( src_second_rc == rc_int && dst_second_rc == rc_stack ) - return impl_helper(this,cbuf,ra_,do_size,false,ra_->reg2offset(dst_second),src_second,Assembler::stw_op3 ,"STW ",size, st); + if (src_second_rc == rc_int && dst_second_rc == rc_stack) + return impl_helper(this, cbuf, ra_, false, ra_->reg2offset(dst_second), src_second, Assembler::stw_op3, "STW ", size, st); // Check for high word float store - if( src_second_rc == rc_float && dst_second_rc == rc_stack ) - return impl_helper(this,cbuf,ra_,do_size,false,ra_->reg2offset(dst_second),src_second,Assembler::stf_op3 ,"STF ",size, st); + if (src_second_rc == rc_float && dst_second_rc == rc_stack) + return impl_helper(this, cbuf, ra_, false, ra_->reg2offset(dst_second), src_second, Assembler::stf_op3, "STF ", size, st); #endif // !_LP64 Unimplemented(); +} + +uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, + PhaseRegAlloc *ra_, + bool do_size, + outputStream* st) const { + assert(!do_size, "not supported"); + mach_spill_copy_implementation_helper(this, cbuf, ra_, st); return 0; } @@ -1669,19 +1697,19 @@ void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { } uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { - return implementation( NULL, ra_, true, NULL ); + return MachNode::size(ra_); } //============================================================================= #ifndef PRODUCT -void MachNopNode::format( PhaseRegAlloc *, outputStream *st ) const { +void MachNopNode::format(PhaseRegAlloc *, outputStream *st) const { st->print("NOP \t# %d bytes pad for loops and calls", 4 * _count); } #endif -void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc * ) const { +void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *) const { MacroAssembler _masm(&cbuf); - for(int i = 0; i < _count; i += 1) { + for (int i = 0; i < _count; i += 1) { __ nop(); } } @@ -5197,7 +5225,6 @@ instruct stkI_to_regF(regF dst, stackSlotI src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDF $src,$dst\t! stkI to regF" %} opcode(Assembler::ldf_op3); ins_encode(simple_form3_mem_reg(src, dst)); @@ -5208,7 +5235,6 @@ instruct stkL_to_regD(regD dst, stackSlotL src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDDF $src,$dst\t! stkL to regD" %} opcode(Assembler::lddf_op3); ins_encode(simple_form3_mem_reg(src, dst)); @@ -5219,7 +5245,6 @@ instruct regF_to_stkI(stackSlotI dst, regF src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STF $src,$dst\t! regF to stkI" %} opcode(Assembler::stf_op3); ins_encode(simple_form3_mem_reg(dst, src)); @@ -5230,7 +5255,6 @@ instruct regD_to_stkL(stackSlotL dst, regD src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STDF $src,$dst\t! regD to stkL" %} opcode(Assembler::stdf_op3); ins_encode(simple_form3_mem_reg(dst, src)); @@ -5240,7 +5264,6 @@ instruct regD_to_stkL(stackSlotL dst, regD src) %{ instruct regI_to_stkLHi(stackSlotL dst, iRegI src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST*2); - size(8); format %{ "STW $src,$dst.hi\t! long\n\t" "STW R_G0,$dst.lo" %} opcode(Assembler::stw_op3); @@ -5252,7 +5275,6 @@ instruct regL_to_stkD(stackSlotD dst, iRegL src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$dst\t! regL to stkD" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -5266,7 +5288,6 @@ instruct stkI_to_regI( iRegI dst, stackSlotI src ) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDUW $src,$dst\t!stk" %} opcode(Assembler::lduw_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -5278,7 +5299,6 @@ instruct regI_to_stkI( stackSlotI dst, iRegI src ) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$dst\t!stk" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -5290,7 +5310,6 @@ instruct stkL_to_regL( iRegL dst, stackSlotL src ) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDX $src,$dst\t! long" %} opcode(Assembler::ldx_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -5302,7 +5321,6 @@ instruct regL_to_stkL(stackSlotL dst, iRegL src) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$dst\t! long" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -5314,7 +5332,6 @@ instruct regL_to_stkL(stackSlotL dst, iRegL src) %{ instruct stkP_to_regP( iRegP dst, stackSlotP src ) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDX $src,$dst\t!ptr" %} opcode(Assembler::ldx_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -5325,7 +5342,6 @@ instruct stkP_to_regP( iRegP dst, stackSlotP src ) %{ instruct regP_to_stkP(stackSlotP dst, iRegP src) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$dst\t!ptr" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -5771,7 +5787,6 @@ instruct loadL_unaligned(iRegL dst, memory mem, o7RegI tmp) %{ match(Set dst (LoadL_unaligned mem)); effect(KILL tmp); ins_cost(MEMORY_REF_COST*2+DEFAULT_COST); - size(16); format %{ "LDUW $mem+4,R_O7\t! misaligned long\n" "\tLDUW $mem ,$dst\n" "\tSLLX #32, $dst, $dst\n" @@ -5786,7 +5801,6 @@ instruct loadRange(iRegI dst, memory mem) %{ match(Set dst (LoadRange mem)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDUW $mem,$dst\t! range" %} opcode(Assembler::lduw_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); @@ -5797,7 +5811,6 @@ instruct loadRange(iRegI dst, memory mem) %{ instruct loadI_freg(regF dst, memory mem) %{ match(Set dst (LoadI mem)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDF $mem,$dst\t! for fitos/fitod" %} opcode(Assembler::ldf_op3); @@ -5876,7 +5889,6 @@ instruct loadD(regD dst, memory mem) %{ match(Set dst (LoadD mem)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDDF $mem,$dst" %} opcode(Assembler::lddf_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); @@ -5887,7 +5899,6 @@ instruct loadD(regD dst, memory mem) %{ instruct loadD_unaligned(regD_low dst, memory mem ) %{ match(Set dst (LoadD_unaligned mem)); ins_cost(MEMORY_REF_COST*2+DEFAULT_COST); - size(8); format %{ "LDF $mem ,$dst.hi\t! misaligned double\n" "\tLDF $mem+4,$dst.lo\t!" %} opcode(Assembler::ldf_op3); @@ -5900,7 +5911,6 @@ instruct loadF(regF dst, memory mem) %{ match(Set dst (LoadF mem)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDF $mem,$dst" %} opcode(Assembler::ldf_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); @@ -6119,7 +6129,6 @@ instruct prefetchAlloc( memory mem ) %{ predicate(AllocatePrefetchInstr == 0); match( PrefetchAllocation mem ); ins_cost(MEMORY_REF_COST); - size(4); format %{ "PREFETCH $mem,2\t! Prefetch allocation" %} opcode(Assembler::prefetch_op3); @@ -6175,7 +6184,6 @@ instruct storeB(memory mem, iRegI src) %{ match(Set mem (StoreB mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STB $src,$mem\t! byte" %} opcode(Assembler::stb_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6186,7 +6194,6 @@ instruct storeB0(memory mem, immI0 src) %{ match(Set mem (StoreB mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STB $src,$mem\t! byte" %} opcode(Assembler::stb_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6197,7 +6204,6 @@ instruct storeCM0(memory mem, immI0 src) %{ match(Set mem (StoreCM mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STB $src,$mem\t! CMS card-mark byte 0" %} opcode(Assembler::stb_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6209,7 +6215,6 @@ instruct storeC(memory mem, iRegI src) %{ match(Set mem (StoreC mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STH $src,$mem\t! short" %} opcode(Assembler::sth_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6220,7 +6225,6 @@ instruct storeC0(memory mem, immI0 src) %{ match(Set mem (StoreC mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STH $src,$mem\t! short" %} opcode(Assembler::sth_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6232,7 +6236,6 @@ instruct storeI(memory mem, iRegI src) %{ match(Set mem (StoreI mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$mem" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6243,7 +6246,6 @@ instruct storeI(memory mem, iRegI src) %{ instruct storeL(memory mem, iRegL src) %{ match(Set mem (StoreL mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$mem\t! long" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6254,7 +6256,6 @@ instruct storeI0(memory mem, immI0 src) %{ match(Set mem (StoreI mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$mem" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6265,7 +6266,6 @@ instruct storeL0(memory mem, immL0 src) %{ match(Set mem (StoreL mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$mem" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6277,7 +6277,6 @@ instruct storeI_Freg(memory mem, regF src) %{ match(Set mem (StoreI mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STF $src,$mem\t! after fstoi/fdtoi" %} opcode(Assembler::stf_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6288,7 +6287,6 @@ instruct storeI_Freg(memory mem, regF src) %{ instruct storeP(memory dst, sp_ptr_RegP src) %{ match(Set dst (StoreP dst src)); ins_cost(MEMORY_REF_COST); - size(4); #ifndef _LP64 format %{ "STW $src,$dst\t! ptr" %} @@ -6304,7 +6302,6 @@ instruct storeP(memory dst, sp_ptr_RegP src) %{ instruct storeP0(memory dst, immP0 src) %{ match(Set dst (StoreP dst src)); ins_cost(MEMORY_REF_COST); - size(4); #ifndef _LP64 format %{ "STW $src,$dst\t! ptr" %} @@ -6379,7 +6376,6 @@ instruct storeD( memory mem, regD src) %{ match(Set mem (StoreD mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STDF $src,$mem" %} opcode(Assembler::stdf_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6390,7 +6386,6 @@ instruct storeD0( memory mem, immD0 src) %{ match(Set mem (StoreD mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$mem" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6402,7 +6397,6 @@ instruct storeF( memory mem, regF src) %{ match(Set mem (StoreF mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STF $src,$mem" %} opcode(Assembler::stf_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6413,7 +6407,6 @@ instruct storeF0( memory mem, immF0 src) %{ match(Set mem (StoreF mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$mem\t! storeF0" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -7068,7 +7061,6 @@ instruct loadPLocked(iRegP dst, memory mem) %{ ins_cost(MEMORY_REF_COST); #ifndef _LP64 - size(4); format %{ "LDUW $mem,$dst\t! ptr" %} opcode(Assembler::lduw_op3, 0, REGP_OP); #else @@ -8138,7 +8130,6 @@ instruct MoveF2I_stack_reg(iRegI dst, stackSlotF src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDUW $src,$dst\t! MoveF2I" %} opcode(Assembler::lduw_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -8150,7 +8141,6 @@ instruct MoveI2F_stack_reg(regF dst, stackSlotI src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDF $src,$dst\t! MoveI2F" %} opcode(Assembler::ldf_op3); ins_encode(simple_form3_mem_reg(src, dst)); @@ -8162,7 +8152,6 @@ instruct MoveD2L_stack_reg(iRegL dst, stackSlotD src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDX $src,$dst\t! MoveD2L" %} opcode(Assembler::ldx_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -8174,7 +8163,6 @@ instruct MoveL2D_stack_reg(regD dst, stackSlotL src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDDF $src,$dst\t! MoveL2D" %} opcode(Assembler::lddf_op3); ins_encode(simple_form3_mem_reg(src, dst)); @@ -8186,7 +8174,6 @@ instruct MoveF2I_reg_stack(stackSlotI dst, regF src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STF $src,$dst\t! MoveF2I" %} opcode(Assembler::stf_op3); ins_encode(simple_form3_mem_reg(dst, src)); @@ -8198,7 +8185,6 @@ instruct MoveI2F_reg_stack(stackSlotF dst, iRegI src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$dst\t! MoveI2F" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -8210,7 +8196,6 @@ instruct MoveD2L_reg_stack(stackSlotL dst, regD src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STDF $src,$dst\t! MoveD2L" %} opcode(Assembler::stdf_op3); ins_encode(simple_form3_mem_reg(dst, src)); @@ -8222,7 +8207,6 @@ instruct MoveL2D_reg_stack(stackSlotD dst, iRegL src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$dst\t! MoveL2D" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -8427,7 +8411,6 @@ instruct convI2D_reg(regD_low dst, iRegI src) %{ instruct convI2D_mem(regD_low dst, memory mem) %{ match(Set dst (ConvI2D (LoadI mem))); ins_cost(DEFAULT_COST + MEMORY_REF_COST); - size(8); format %{ "LDF $mem,$dst\n\t" "FITOD $dst,$dst" %} opcode(Assembler::ldf_op3, Assembler::fitod_opf); @@ -8468,7 +8451,6 @@ instruct convI2F_reg(regF dst, iRegI src) %{ instruct convI2F_mem( regF dst, memory mem ) %{ match(Set dst (ConvI2F (LoadI mem))); ins_cost(DEFAULT_COST + MEMORY_REF_COST); - size(8); format %{ "LDF $mem,$dst\n\t" "FITOS $dst,$dst" %} opcode(Assembler::ldf_op3, Assembler::fitos_opf); From f9a6dbd5fd802b319c897b00c3cfda3e1e397d8a Mon Sep 17 00:00:00 2001 From: Christian Thalinger Date: Fri, 26 Feb 2016 11:13:25 -1000 Subject: [PATCH 041/183] 8150738: [JVMCI] runtime/CommandLine/TraceExceptionsTest.java fails with: java.lang.RuntimeException: '' missing Reviewed-by: coleenp --- hotspot/src/share/vm/jvmci/jvmciRuntime.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp index 716f73c06b1..d5a10f4660f 100644 --- a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp @@ -293,13 +293,11 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t // tracing if (log_is_enabled(Info, exceptions)) { ResourceMark rm; - log_info(exceptions)("Exception <%s> (" INTPTR_FORMAT ") thrown in" - " compiled method <%s> at PC " INTPTR_FORMAT - " for thread " INTPTR_FORMAT, - exception->print_value_string(), - p2i((address)exception()), - nm->method()->print_value_string(), p2i(pc), - p2i(thread)); + stringStream tempst; + tempst.print("compiled method <%s>\n" + " at PC" INTPTR_FORMAT " for thread " INTPTR_FORMAT, + nm->method()->print_value_string(), p2i(pc), p2i(thread)); + Exceptions::log_exception(exception, tempst); } // for AbortVMOnException flag NOT_PRODUCT(Exceptions::debug_check_abort(exception)); From babca8523287e182f5683992935c11bce2d754d6 Mon Sep 17 00:00:00 2001 From: Zoltan Majo Date: Mon, 29 Feb 2016 13:02:10 +0100 Subject: [PATCH 042/183] 8150349: Reduce the execution time of the hotspot_compiler_3 group Exclude long-running intrinsic-related tests that check functionality that is not likely to be changed soon. Reviewed-by: kvn, neliasso --- hotspot/test/TEST.groups | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups index f7d983f5a8f..11b95da776b 100644 --- a/hotspot/test/TEST.groups +++ b/hotspot/test/TEST.groups @@ -297,7 +297,8 @@ hotspot_compiler_3 = \ compiler/types/ \ compiler/uncommontrap/ \ compiler/unsafe/ \ - -compiler/intrinsics/bmi/verifycode \ + -compiler/intrinsics/adler32 \ + -compiler/intrinsics/bmi \ -compiler/intrinsics/mathexact \ -compiler/intrinsics/multiplytolen \ -compiler/intrinsics/sha \ From ea5a3565b8618fd0746082e0d82e423f47fcd7ce Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Mon, 29 Feb 2016 15:05:45 +0100 Subject: [PATCH 043/183] 8150720: Cleanup code around PrintOptoStatistics Reviewed-by: kvn, shade, vlivanov --- hotspot/src/share/vm/opto/graphKit.cpp | 17 ++++++---- hotspot/src/share/vm/opto/ifnode.cpp | 20 ++++++++---- hotspot/src/share/vm/opto/lcm.cpp | 2 ++ hotspot/src/share/vm/opto/matcher.cpp | 2 ++ hotspot/src/share/vm/opto/node.cpp | 28 ++-------------- hotspot/src/share/vm/opto/parse.hpp | 10 ------ hotspot/src/share/vm/opto/parse1.cpp | 45 ++++++++++++-------------- hotspot/src/share/vm/opto/parse2.cpp | 8 +++-- 8 files changed, 56 insertions(+), 76 deletions(-) diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index a47897db8c1..73f7c3e1254 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -1179,8 +1179,10 @@ Node* GraphKit::load_array_length(Node* array) { // Helper function to do a NULL pointer check. Returned value is // the incoming address with NULL casted away. You are allowed to use the // not-null value only if you are control dependent on the test. +#ifndef PRODUCT extern int explicit_null_checks_inserted, explicit_null_checks_elided; +#endif Node* GraphKit::null_check_common(Node* value, BasicType type, // optional arguments for variations: bool assert_null, @@ -1193,7 +1195,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, value = cast_not_null(value); // Make it appear to be non-null (4962416). return value; } - explicit_null_checks_inserted++; + NOT_PRODUCT(explicit_null_checks_inserted++); // Construct NULL check Node *chk = NULL; @@ -1233,7 +1235,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, // See if the type is contained in NULL_PTR. // If so, then the value is already null. if (t->higher_equal(TypePtr::NULL_PTR)) { - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); return value; // Elided null assert quickly! } } else { @@ -1242,7 +1244,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, // type. In other words, "value" was not-null. if (t->meet(TypePtr::NULL_PTR) != t->remove_speculative()) { // same as: if (!TypePtr::NULL_PTR->higher_equal(t)) ... - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); return value; // Elided null check quickly! } } @@ -1282,7 +1284,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, set_control(cfg); Node *res = cast_not_null(value); set_control(oldcontrol); - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); return res; } cfg = IfNode::up_one_dom(cfg, /*linear_only=*/ true); @@ -1326,15 +1328,18 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, IfNode* iff = create_and_map_if(control(), tst, ok_prob, COUNT_UNKNOWN); Node* null_true = _gvn.transform( new IfFalseNode(iff)); set_control( _gvn.transform( new IfTrueNode(iff))); - if (null_true == top()) +#ifndef PRODUCT + if (null_true == top()) { explicit_null_checks_elided++; + } +#endif (*null_control) = null_true; } else { BuildCutout unless(this, tst, ok_prob); // Check for optimizer eliding test at parse time if (stopped()) { // Failure not possible; do not bother making uncommon trap. - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); } else if (assert_null) { uncommon_trap(reason, Deoptimization::Action_make_not_entrant, diff --git a/hotspot/src/share/vm/opto/ifnode.cpp b/hotspot/src/share/vm/opto/ifnode.cpp index a2cea88273f..9e315739008 100644 --- a/hotspot/src/share/vm/opto/ifnode.cpp +++ b/hotspot/src/share/vm/opto/ifnode.cpp @@ -40,7 +40,9 @@ // Optimization - Graph Style +#ifndef PRODUCT extern int explicit_null_checks_elided; +#endif //============================================================================= //------------------------------Value------------------------------------------ @@ -1504,24 +1506,28 @@ Node* IfNode::search_identical(int dist) { Node* prev_dom = this; int op = Opcode(); // Search up the dominator tree for an If with an identical test - while( dom->Opcode() != op || // Not same opcode? + while (dom->Opcode() != op || // Not same opcode? dom->in(1) != in(1) || // Not same input 1? (req() == 3 && dom->in(2) != in(2)) || // Not same input 2? - prev_dom->in(0) != dom ) { // One path of test does not dominate? - if( dist < 0 ) return NULL; + prev_dom->in(0) != dom) { // One path of test does not dominate? + if (dist < 0) return NULL; dist--; prev_dom = dom; - dom = up_one_dom( dom ); - if( !dom ) return NULL; + dom = up_one_dom(dom); + if (!dom) return NULL; } // Check that we did not follow a loop back to ourselves - if( this == dom ) + if (this == dom) { return NULL; + } - if( dist > 2 ) // Add to count of NULL checks elided +#ifndef PRODUCT + if (dist > 2) { // Add to count of NULL checks elided explicit_null_checks_elided++; + } +#endif return prev_dom; } diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp index 3edfc5e0ef0..431bba14c7e 100644 --- a/hotspot/src/share/vm/opto/lcm.cpp +++ b/hotspot/src/share/vm/opto/lcm.cpp @@ -348,8 +348,10 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo } // ---- Found an implicit null check +#ifndef PRODUCT extern int implicit_null_checks; implicit_null_checks++; +#endif if( is_decoden ) { // Check if we need to hoist decodeHeapOop_not_null first. diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index edb69afb43d..1df9f7ca1c0 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -2415,8 +2415,10 @@ void Matcher::collect_null_checks( Node *proj, Node *orig_proj ) { bool push_it = false; if( proj->Opcode() == Op_IfTrue ) { +#ifndef PRODUCT extern int all_null_checks_found; all_null_checks_found++; +#endif if( b->_test._test == BoolTest::ne ) { push_it = true; } diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp index 42ca23d212a..78dcacc550b 100644 --- a/hotspot/src/share/vm/opto/node.cpp +++ b/hotspot/src/share/vm/opto/node.cpp @@ -576,17 +576,11 @@ void Node::setup_is_top() { //------------------------------~Node------------------------------------------ // Fancy destructor; eagerly attempt to reclaim Node numberings and storage -extern int reclaim_idx ; -extern int reclaim_in ; -extern int reclaim_node; void Node::destruct() { // Eagerly reclaim unique Node numberings Compile* compile = Compile::current(); if ((uint)_idx+1 == compile->unique()) { compile->set_unique(compile->unique()-1); -#ifdef ASSERT - reclaim_idx++; -#endif } // Clear debug info: Node_Notes* nn = compile->node_notes_at(_idx); @@ -604,43 +598,25 @@ void Node::destruct() { int out_edge_size = _outmax*sizeof(void*); char *edge_end = ((char*)_in) + edge_size; char *out_array = (char*)(_out == NO_OUT_ARRAY? NULL: _out); - char *out_edge_end = out_array + out_edge_size; int node_size = size_of(); // Free the output edge array if (out_edge_size > 0) { -#ifdef ASSERT - if( out_edge_end == compile->node_arena()->hwm() ) - reclaim_in += out_edge_size; // count reclaimed out edges with in edges -#endif compile->node_arena()->Afree(out_array, out_edge_size); } // Free the input edge array and the node itself if( edge_end == (char*)this ) { -#ifdef ASSERT - if( edge_end+node_size == compile->node_arena()->hwm() ) { - reclaim_in += edge_size; - reclaim_node+= node_size; - } -#else // It was; free the input array and object all in one hit +#ifndef ASSERT compile->node_arena()->Afree(_in,edge_size+node_size); #endif } else { - // Free just the input array -#ifdef ASSERT - if( edge_end == compile->node_arena()->hwm() ) - reclaim_in += edge_size; -#endif compile->node_arena()->Afree(_in,edge_size); // Free just the object -#ifdef ASSERT - if( ((char*)this) + node_size == compile->node_arena()->hwm() ) - reclaim_node+= node_size; -#else +#ifndef ASSERT compile->node_arena()->Afree(this,node_size); #endif } diff --git a/hotspot/src/share/vm/opto/parse.hpp b/hotspot/src/share/vm/opto/parse.hpp index c8a35c9ba53..b26a59f8497 100644 --- a/hotspot/src/share/vm/opto/parse.hpp +++ b/hotspot/src/share/vm/opto/parse.hpp @@ -104,13 +104,6 @@ public: // For temporary (stack-allocated, stateless) ilts: InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, float site_invoke_ratio, int max_inline_level); - // InlineTree enum - enum InlineStyle { - Inline_do_not_inline = 0, // - Inline_cha_is_monomorphic = 1, // - Inline_type_profile_monomorphic = 2 // - }; - // See if it is OK to inline. // The receiver is the inline tree for the caller. // @@ -349,9 +342,6 @@ class Parse : public GraphKit { Block* _block; // block currently getting parsed ciBytecodeStream _iter; // stream of this method's bytecodes - int _blocks_merged; // Progress meter: state merges from BB preds - int _blocks_parsed; // Progress meter: BBs actually parsed - const FastLockNode* _synch_lock; // FastLockNode for synchronized method #ifndef PRODUCT diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index e051b5e1e5c..503f3c7f400 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -45,6 +45,7 @@ // the most. Some of the non-static variables are needed in bytecodeInfo.cpp // and eventually should be encapsulated in a proper class (gri 8/18/98). +#ifndef PRODUCT int nodes_created = 0; int methods_parsed = 0; int methods_seen = 0; @@ -53,42 +54,42 @@ int blocks_seen = 0; int explicit_null_checks_inserted = 0; int explicit_null_checks_elided = 0; -int all_null_checks_found = 0, implicit_null_checks = 0; -int implicit_null_throws = 0; +int all_null_checks_found = 0; +int implicit_null_checks = 0; -int reclaim_idx = 0; -int reclaim_in = 0; -int reclaim_node = 0; - -#ifndef PRODUCT bool Parse::BytecodeParseHistogram::_initialized = false; uint Parse::BytecodeParseHistogram::_bytecodes_parsed [Bytecodes::number_of_codes]; uint Parse::BytecodeParseHistogram::_nodes_constructed[Bytecodes::number_of_codes]; uint Parse::BytecodeParseHistogram::_nodes_transformed[Bytecodes::number_of_codes]; uint Parse::BytecodeParseHistogram::_new_values [Bytecodes::number_of_codes]; -#endif //------------------------------print_statistics------------------------------- -#ifndef PRODUCT void Parse::print_statistics() { tty->print_cr("--- Compiler Statistics ---"); tty->print("Methods seen: %d Methods parsed: %d", methods_seen, methods_parsed); tty->print(" Nodes created: %d", nodes_created); tty->cr(); - if (methods_seen != methods_parsed) + if (methods_seen != methods_parsed) { tty->print_cr("Reasons for parse failures (NOT cumulative):"); + } tty->print_cr("Blocks parsed: %d Blocks seen: %d", blocks_parsed, blocks_seen); - if( explicit_null_checks_inserted ) - tty->print_cr("%d original NULL checks - %d elided (%2d%%); optimizer leaves %d,", explicit_null_checks_inserted, explicit_null_checks_elided, (100*explicit_null_checks_elided)/explicit_null_checks_inserted, all_null_checks_found); - if( all_null_checks_found ) + if (explicit_null_checks_inserted) { + tty->print_cr("%d original NULL checks - %d elided (%2d%%); optimizer leaves %d,", + explicit_null_checks_inserted, explicit_null_checks_elided, + (100*explicit_null_checks_elided)/explicit_null_checks_inserted, + all_null_checks_found); + } + if (all_null_checks_found) { tty->print_cr("%d made implicit (%2d%%)", implicit_null_checks, (100*implicit_null_checks)/all_null_checks_found); - if( implicit_null_throws ) + } + if (SharedRuntime::_implicit_null_throws) { tty->print_cr("%d implicit null exceptions at runtime", - implicit_null_throws); + SharedRuntime::_implicit_null_throws); + } - if( PrintParseStatistics && BytecodeParseHistogram::initialized() ) { + if (PrintParseStatistics && BytecodeParseHistogram::initialized()) { BytecodeParseHistogram::print(); } } @@ -495,7 +496,7 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) C->dependencies()->assert_evol_method(method()); } - methods_seen++; + NOT_PRODUCT(methods_seen++); // Do some special top-level things. if (depth() == 1 && C->is_osr_compilation()) { @@ -530,8 +531,8 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) } #endif - methods_parsed++; #ifndef PRODUCT + methods_parsed++; // add method size here to guarantee that inlined methods are added too if (CITime) _total_bytes_compiled += method()->code_size(); @@ -652,7 +653,7 @@ void Parse::do_all_blocks() { continue; } - blocks_parsed++; + NOT_PRODUCT(blocks_parsed++); progress = true; if (block->is_loop_head() || block->is_handler() || has_irreducible && !block->is_ready()) { @@ -712,9 +713,9 @@ void Parse::do_all_blocks() { } } +#ifndef PRODUCT blocks_seen += block_count(); -#ifndef PRODUCT // Make sure there are no half-processed blocks remaining. // Every remaining unprocessed block is dead and may be ignored now. for (int rpo = 0; rpo < block_count(); rpo++) { @@ -1446,7 +1447,6 @@ void Parse::do_one_block() { assert(block()->is_merged(), "must be merged before being parsed"); block()->mark_parsed(); - ++_blocks_parsed; // Set iterator to start of block. iter().reset_to_bci(block()->start()); @@ -1596,9 +1596,6 @@ void Parse::merge_common(Parse::Block* target, int pnum) { return; } - // Record that a new block has been merged. - ++_blocks_merged; - // Make a region if we know there are multiple or unpredictable inputs. // (Also, if this is a plain fall-through, we might see another region, // which must not be allowed into this block's map.) diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index e03abd4f931..8004ef246e5 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -44,8 +44,10 @@ #include "runtime/deoptimization.hpp" #include "runtime/sharedRuntime.hpp" +#ifndef PRODUCT extern int explicit_null_checks_inserted, explicit_null_checks_elided; +#endif //---------------------------------array_load---------------------------------- void Parse::array_load(BasicType elem_type) { @@ -997,7 +999,7 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { return; } - explicit_null_checks_inserted++; + NOT_PRODUCT(explicit_null_checks_inserted++); // Generate real control flow Node *tst = _gvn.transform( new BoolNode( c, btest ) ); @@ -1013,7 +1015,7 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { set_control(iftrue); if (stopped()) { // Path is dead? - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); if (C->eliminate_boxing()) { // Mark the successor block as parsed branch_block->next_path_num(); @@ -1033,7 +1035,7 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { set_control(iffalse); if (stopped()) { // Path is dead? - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); if (C->eliminate_boxing()) { // Mark the successor block as parsed next_block->next_path_num(); From bb51ea7a06a1c95184940b26e45957731b2ae5f1 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Mon, 29 Feb 2016 23:46:55 +0300 Subject: [PATCH 044/183] 8150543: Mismatched access detection is inaccurate Reviewed-by: kvn, shade --- hotspot/src/share/vm/opto/library_call.cpp | 8 +- hotspot/src/share/vm/opto/memnode.cpp | 18 +- .../unsafe/UnsafeGetConstantField.java | 3 + .../unsafe/UnsafeGetStableArrayElement.java | 278 +++++++++++++++++- 4 files changed, 284 insertions(+), 23 deletions(-) diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index de751bc1a97..240321cb231 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -2541,10 +2541,12 @@ bool LibraryCallKit::inline_unsafe_access(const bool is_native_ptr, bool is_stor if (alias_type->element() != NULL || alias_type->field() != NULL) { BasicType bt; if (alias_type->element() != NULL) { - const Type* element = alias_type->element(); + // Use address type to get the element type. Alias type doesn't provide + // enough information (e.g., doesn't differentiate between byte[] and boolean[]). + const Type* element = adr_type->is_aryptr()->elem(); bt = element->isa_narrowoop() ? T_OBJECT : element->array_element_basic_type(); } else { - bt = alias_type->field()->type()->basic_type(); + bt = alias_type->field()->layout_type(); } if (bt == T_ARRAY) { // accessing an array field with getObject is not a mismatch @@ -2561,7 +2563,7 @@ bool LibraryCallKit::inline_unsafe_access(const bool is_native_ptr, bool is_stor // Try to constant fold a load from a constant field ciField* field = alias_type->field(); if (heap_base_oop != top() && - field != NULL && field->is_constant() && field->layout_type() == type) { + field != NULL && field->is_constant() && !mismatched) { // final or stable field const Type* con_type = Type::make_constant(alias_type->field(), heap_base_oop); if (con_type != NULL) { diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 55ca4581485..2d2b40d334e 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -1582,14 +1582,22 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls, return NULL; } +#ifdef ASSERT static bool is_mismatched_access(ciConstant con, BasicType loadbt) { BasicType conbt = con.basic_type(); - assert(conbt != T_NARROWOOP, "sanity"); - if (loadbt == T_NARROWOOP || loadbt == T_ARRAY) { - loadbt = T_OBJECT; + switch (conbt) { + case T_BOOLEAN: conbt = T_BYTE; break; + case T_ARRAY: conbt = T_OBJECT; break; + } + switch (loadbt) { + case T_BOOLEAN: loadbt = T_BYTE; break; + case T_NARROWOOP: loadbt = T_OBJECT; break; + case T_ARRAY: loadbt = T_OBJECT; break; + case T_ADDRESS: loadbt = T_OBJECT; break; } return (conbt != loadbt); } +#endif // ASSERT // Try to constant-fold a stable array element. static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) { @@ -1599,7 +1607,9 @@ static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicTyp // Decode the results of GraphKit::array_element_address. ciArray* aobj = ary->const_oop()->as_array(); ciConstant con = aobj->element_value_by_offset(off); - if (con.basic_type() != T_ILLEGAL && !is_mismatched_access(con, loadbt) && !con.is_null_or_zero()) { + if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) { + assert(!is_mismatched_access(con, loadbt), + "conbt=%s; loadbt=%s", type2name(con.basic_type()), type2name(loadbt)); const Type* con_type = Type::make_from_constant(con); if (con_type != NULL) { if (con_type->isa_aryptr()) { diff --git a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java index 8c144143d62..c1d6b057e14 100644 --- a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java +++ b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java @@ -27,6 +27,9 @@ * @test * @summary tests on constant folding of unsafe get operations * @library /testlibrary /test/lib + * + * @requires vm.flavor != "client" + * * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions * -Xbatch -XX:-TieredCompilation * -XX:+FoldStableValues diff --git a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java index afdb1a6e7a3..0cf5f44dc85 100644 --- a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java +++ b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java @@ -25,17 +25,15 @@ /* * @test - * @summary tests on constant folding of unsafe get operations + * @summary tests on constant folding of unsafe get operations from stable arrays * @library /testlibrary /test/lib * + * @requires vm.flavor != "client" + * * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions * -Xbatch -XX:-TieredCompilation * -XX:+FoldStableValues - * UnsafeGetStableArrayElement - * - * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions - * -Xbatch -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+FoldStableValues + * -XX:CompileCommand=dontinline,*Test::test* * UnsafeGetStableArrayElement */ import jdk.internal.misc.Unsafe; @@ -46,23 +44,271 @@ import static jdk.internal.misc.Unsafe.*; import static jdk.test.lib.Asserts.*; public class UnsafeGetStableArrayElement { - @Stable static final byte[] STABLE_BYTE_ARRAY = new byte[] { 0, 1, -128, 127}; + @Stable static final boolean[] STABLE_BOOLEAN_ARRAY = new boolean[16]; + @Stable static final byte[] STABLE_BYTE_ARRAY = new byte[16]; + @Stable static final short[] STABLE_SHORT_ARRAY = new short[8]; + @Stable static final char[] STABLE_CHAR_ARRAY = new char[8]; + @Stable static final int[] STABLE_INT_ARRAY = new int[4]; + @Stable static final long[] STABLE_LONG_ARRAY = new long[2]; + @Stable static final float[] STABLE_FLOAT_ARRAY = new float[4]; + @Stable static final double[] STABLE_DOUBLE_ARRAY = new double[2]; + @Stable static final Object[] STABLE_OBJECT_ARRAY = new Object[4]; + static { + Setter.reset(); + } static final Unsafe U = Unsafe.getUnsafe(); - static int testChar() { - return U.getChar(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET + 0 * ARRAY_CHAR_INDEX_SCALE) + - U.getChar(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET + 1 * ARRAY_CHAR_INDEX_SCALE); - } + static class Setter { + private static void setZ(boolean defaultVal) { STABLE_BOOLEAN_ARRAY[0] = defaultVal ? false : true; } + private static void setB(boolean defaultVal) { STABLE_BYTE_ARRAY[0] = defaultVal ? 0 : Byte.MAX_VALUE; } + private static void setS(boolean defaultVal) { STABLE_SHORT_ARRAY[0] = defaultVal ? 0 : Short.MAX_VALUE; } + private static void setC(boolean defaultVal) { STABLE_CHAR_ARRAY[0] = defaultVal ? 0 : Character.MAX_VALUE; } + private static void setI(boolean defaultVal) { STABLE_INT_ARRAY[0] = defaultVal ? 0 : Integer.MAX_VALUE; } + private static void setJ(boolean defaultVal) { STABLE_LONG_ARRAY[0] = defaultVal ? 0 : Long.MAX_VALUE; } + private static void setF(boolean defaultVal) { STABLE_FLOAT_ARRAY[0] = defaultVal ? 0 : Float.MAX_VALUE; } + private static void setD(boolean defaultVal) { STABLE_DOUBLE_ARRAY[0] = defaultVal ? 0 : Double.MAX_VALUE; } + private static void setL(boolean defaultVal) { STABLE_OBJECT_ARRAY[0] = defaultVal ? null : new Object(); } - static void run(Callable c) throws Exception { - Object first = c.call(); - for (int i = 0; i < 20_000; i++) { - assertEQ(first, c.call()); + static void reset() { + setZ(false); + setB(false); + setS(false); + setC(false); + setI(false); + setJ(false); + setF(false); + setD(false); + setL(false); } } + static class Test { + static void changeZ() { Setter.setZ(true); } + static void changeB() { Setter.setB(true); } + static void changeS() { Setter.setS(true); } + static void changeC() { Setter.setC(true); } + static void changeI() { Setter.setI(true); } + static void changeJ() { Setter.setJ(true); } + static void changeF() { Setter.setF(true); } + static void changeD() { Setter.setD(true); } + static void changeL() { Setter.setL(true); } + + static boolean testZ_Z() { return U.getBoolean(STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static byte testZ_B() { return U.getByte( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static short testZ_S() { return U.getShort( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static char testZ_C() { return U.getChar( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static int testZ_I() { return U.getInt( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static long testZ_J() { return U.getLong( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static float testZ_F() { return U.getFloat( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static double testZ_D() { return U.getDouble( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + + static boolean testB_Z() { return U.getBoolean(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static byte testB_B() { return U.getByte( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static short testB_S() { return U.getShort( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static char testB_C() { return U.getChar( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static int testB_I() { return U.getInt( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static long testB_J() { return U.getLong( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static float testB_F() { return U.getFloat( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static double testB_D() { return U.getDouble( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + + static boolean testS_Z() { return U.getBoolean(STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static byte testS_B() { return U.getByte( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static short testS_S() { return U.getShort( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static char testS_C() { return U.getChar( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static int testS_I() { return U.getInt( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static long testS_J() { return U.getLong( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static float testS_F() { return U.getFloat( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static double testS_D() { return U.getDouble( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + + static boolean testC_Z() { return U.getBoolean(STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static byte testC_B() { return U.getByte( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static short testC_S() { return U.getShort( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static char testC_C() { return U.getChar( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static int testC_I() { return U.getInt( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static long testC_J() { return U.getLong( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static float testC_F() { return U.getFloat( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static double testC_D() { return U.getDouble( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + + static boolean testI_Z() { return U.getBoolean(STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static byte testI_B() { return U.getByte( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static short testI_S() { return U.getShort( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static char testI_C() { return U.getChar( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static int testI_I() { return U.getInt( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static long testI_J() { return U.getLong( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static float testI_F() { return U.getFloat( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static double testI_D() { return U.getDouble( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + + static boolean testJ_Z() { return U.getBoolean(STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static byte testJ_B() { return U.getByte( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static short testJ_S() { return U.getShort( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static char testJ_C() { return U.getChar( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static int testJ_I() { return U.getInt( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static long testJ_J() { return U.getLong( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static float testJ_F() { return U.getFloat( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static double testJ_D() { return U.getDouble( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + + static boolean testF_Z() { return U.getBoolean(STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static byte testF_B() { return U.getByte( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static short testF_S() { return U.getShort( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static char testF_C() { return U.getChar( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static int testF_I() { return U.getInt( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static long testF_J() { return U.getLong( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static float testF_F() { return U.getFloat( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static double testF_D() { return U.getDouble( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + + static boolean testD_Z() { return U.getBoolean(STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static byte testD_B() { return U.getByte( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static short testD_S() { return U.getShort( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static char testD_C() { return U.getChar( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static int testD_I() { return U.getInt( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static long testD_J() { return U.getLong( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static float testD_F() { return U.getFloat( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static double testD_D() { return U.getDouble( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + + static Object testL_L() { return U.getObject( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static boolean testL_Z() { return U.getBoolean(STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static byte testL_B() { return U.getByte( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static short testL_S() { return U.getShort( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static char testL_C() { return U.getChar( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static int testL_I() { return U.getInt( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static long testL_J() { return U.getLong( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static float testL_F() { return U.getFloat( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static double testL_D() { return U.getDouble( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + + static short testS_U() { return U.getShortUnaligned(STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET + 1); } + static char testC_U() { return U.getCharUnaligned( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET + 1); } + static int testI_U() { return U.getIntUnaligned( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET + 1); } + static long testJ_U() { return U.getLongUnaligned( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET + 1); } + } + + static void run(Callable c, Runnable sameResultAction, Runnable changeResultAction) throws Exception { + Object first = c.call(); + + // Trigger compilation. + for (int i = 0; i < 20_000; i++) { + // Don't compare results here, since most of Test::testL_* results vary across iterations (due to GC). + c.call(); + } + + if (sameResultAction != null) { + sameResultAction.run(); + assertEQ(first, c.call()); + } + + if (changeResultAction != null) { + changeResultAction.run(); + assertNE(first, c.call()); + assertEQ(c.call(), c.call()); + } + } + + static void testMatched(Callable c, Runnable setDefaultAction) throws Exception { + run(c, setDefaultAction, null); + Setter.reset(); + } + + static void testMismatched(Callable c, Runnable setDefaultAction) throws Exception { + run(c, null, setDefaultAction); + Setter.reset(); + } + public static void main(String[] args) throws Exception { - run(UnsafeGetStableArrayElement::testChar); + // boolean[], aligned accesses + testMatched( Test::testZ_Z, Test::changeZ); + testMismatched(Test::testZ_B, Test::changeZ); + testMismatched(Test::testZ_S, Test::changeZ); + testMismatched(Test::testZ_C, Test::changeZ); + testMismatched(Test::testZ_I, Test::changeZ); + testMismatched(Test::testZ_J, Test::changeZ); + testMismatched(Test::testZ_F, Test::changeZ); + testMismatched(Test::testZ_D, Test::changeZ); + + // byte[], aligned accesses + testMismatched(Test::testB_Z, Test::changeB); + testMatched( Test::testB_B, Test::changeB); + testMismatched(Test::testB_S, Test::changeB); + testMismatched(Test::testB_C, Test::changeB); + testMismatched(Test::testB_I, Test::changeB); + testMismatched(Test::testB_J, Test::changeB); + testMismatched(Test::testB_F, Test::changeB); + testMismatched(Test::testB_D, Test::changeB); + + // short[], aligned accesses + testMismatched(Test::testS_Z, Test::changeS); + testMismatched(Test::testS_B, Test::changeS); + testMatched( Test::testS_S, Test::changeS); + testMismatched(Test::testS_C, Test::changeS); + testMismatched(Test::testS_I, Test::changeS); + testMismatched(Test::testS_J, Test::changeS); + testMismatched(Test::testS_F, Test::changeS); + testMismatched(Test::testS_D, Test::changeS); + + // char[], aligned accesses + testMismatched(Test::testC_Z, Test::changeC); + testMismatched(Test::testC_B, Test::changeC); + testMismatched(Test::testC_S, Test::changeC); + testMatched( Test::testC_C, Test::changeC); + testMismatched(Test::testC_I, Test::changeC); + testMismatched(Test::testC_J, Test::changeC); + testMismatched(Test::testC_F, Test::changeC); + testMismatched(Test::testC_D, Test::changeC); + + // int[], aligned accesses + testMismatched(Test::testI_Z, Test::changeI); + testMismatched(Test::testI_B, Test::changeI); + testMismatched(Test::testI_S, Test::changeI); + testMismatched(Test::testI_C, Test::changeI); + testMatched( Test::testI_I, Test::changeI); + testMismatched(Test::testI_J, Test::changeI); + testMismatched(Test::testI_F, Test::changeI); + testMismatched(Test::testI_D, Test::changeI); + + // long[], aligned accesses + testMismatched(Test::testJ_Z, Test::changeJ); + testMismatched(Test::testJ_B, Test::changeJ); + testMismatched(Test::testJ_S, Test::changeJ); + testMismatched(Test::testJ_C, Test::changeJ); + testMismatched(Test::testJ_I, Test::changeJ); + testMatched( Test::testJ_J, Test::changeJ); + testMismatched(Test::testJ_F, Test::changeJ); + testMismatched(Test::testJ_D, Test::changeJ); + + // float[], aligned accesses + testMismatched(Test::testF_Z, Test::changeF); + testMismatched(Test::testF_B, Test::changeF); + testMismatched(Test::testF_S, Test::changeF); + testMismatched(Test::testF_C, Test::changeF); + testMismatched(Test::testF_I, Test::changeF); + testMismatched(Test::testF_J, Test::changeF); + testMatched( Test::testF_F, Test::changeF); + testMismatched(Test::testF_D, Test::changeF); + + // double[], aligned accesses + testMismatched(Test::testD_Z, Test::changeD); + testMismatched(Test::testD_B, Test::changeD); + testMismatched(Test::testD_S, Test::changeD); + testMismatched(Test::testD_C, Test::changeD); + testMismatched(Test::testD_I, Test::changeD); + testMismatched(Test::testD_J, Test::changeD); + testMismatched(Test::testD_F, Test::changeD); + testMatched( Test::testD_D, Test::changeD); + + // Object[], aligned accesses + testMismatched(Test::testL_Z, Test::changeL); + testMismatched(Test::testL_B, Test::changeL); + testMismatched(Test::testL_S, Test::changeL); + testMismatched(Test::testL_C, Test::changeL); + testMismatched(Test::testL_I, Test::changeL); + testMismatched(Test::testL_J, Test::changeL); + testMismatched(Test::testL_F, Test::changeL); + testMismatched(Test::testL_D, Test::changeL); + testMatched( Test::testL_L, Test::changeL); + + // Unaligned accesses + testMismatched(Test::testS_U, Test::changeS); + testMismatched(Test::testC_U, Test::changeC); + testMismatched(Test::testI_U, Test::changeI); + testMismatched(Test::testJ_U, Test::changeJ); } } From f73f7433d015641095e8a10b5f2c6ea15153214e Mon Sep 17 00:00:00 2001 From: Hui Shi Date: Wed, 24 Feb 2016 04:45:50 -0800 Subject: [PATCH 045/183] 8149733: AArch64: refactor array_equals/string_equals Combine similar code for string_equals/char_array_equals/byte_array_equals into same implemenation Reviewed-by: aph, shade --- hotspot/src/cpu/aarch64/vm/aarch64.ad | 25 +- .../cpu/aarch64/vm/macroAssembler_aarch64.cpp | 297 ++++++------------ .../cpu/aarch64/vm/macroAssembler_aarch64.hpp | 12 +- 3 files changed, 118 insertions(+), 216 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index 18ba1e44cf3..e980a2332f3 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -14783,19 +14783,19 @@ instruct string_indexof_con(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, %} instruct string_equals(iRegP_R1 str1, iRegP_R3 str2, iRegI_R4 cnt, - iRegI_R0 result, iRegP_R10 tmp, rFlagsReg cr) + iRegI_R0 result, rFlagsReg cr) %{ predicate(!CompactStrings); match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(KILL tmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); - format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp" %} + format %{ "String Equals $str1,$str2,$cnt -> $result" %} ins_encode %{ // Count is in 8-bit bytes; non-Compact chars are 16 bits. __ asrw($cnt$$Register, $cnt$$Register, 1); - __ string_equals($str1$$Register, $str2$$Register, - $cnt$$Register, $result$$Register, - $tmp$$Register); + __ arrays_equals($str1$$Register, $str2$$Register, + $result$$Register, $cnt$$Register, + 2, /*is_string*/true); %} ins_pipe(pipe_class_memory); %} @@ -14809,9 +14809,10 @@ instruct array_equalsB(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, format %{ "Array Equals $ary1,ary2 -> $result // KILL $tmp" %} ins_encode %{ - __ byte_arrays_equals($ary1$$Register, $ary2$$Register, - $result$$Register, $tmp$$Register); - %} + __ arrays_equals($ary1$$Register, $ary2$$Register, + $result$$Register, $tmp$$Register, + 1, /*is_string*/false); + %} ins_pipe(pipe_class_memory); %} @@ -14824,12 +14825,14 @@ instruct array_equalsC(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, format %{ "Array Equals $ary1,ary2 -> $result // KILL $tmp" %} ins_encode %{ - __ char_arrays_equals($ary1$$Register, $ary2$$Register, - $result$$Register, $tmp$$Register); + __ arrays_equals($ary1$$Register, $ary2$$Register, + $result$$Register, $tmp$$Register, + 2, /*is_string*/false); %} ins_pipe(pipe_class_memory); %} + // encode char[] to byte[] in ISO_8859_1 instruct encode_iso_array(iRegP_R2 src, iRegP_R1 dst, iRegI_R3 len, vRegD_V0 Vtmp1, vRegD_V1 Vtmp2, diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index 8c7f9465622..942518b116b 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -4481,225 +4481,126 @@ void MacroAssembler::string_compare(Register str1, Register str2, BLOCK_COMMENT("} string_compare"); } +// Compare Strings or char/byte arrays. -void MacroAssembler::string_equals(Register str1, Register str2, - Register cnt, Register result, - Register tmp1) { - Label SAME_CHARS, DONE, SHORT_LOOP, SHORT_STRING, - NEXT_WORD; +// is_string is true iff this is a string comparison. - const Register tmp2 = rscratch1; - assert_different_registers(str1, str2, cnt, result, tmp1, tmp2, rscratch2); +// For Strings we're passed the address of the first characters in a1 +// and a2 and the length in cnt1. - BLOCK_COMMENT("string_equals {"); +// For byte and char arrays we're passed the arrays themselves and we +// have to extract length fields and do null checks here. - // Start by assuming that the strings are not equal. - mov(result, zr); +// elem_size is the element size in bytes: either 1 or 2. - // A very short string - cmpw(cnt, 4); - br(Assembler::LT, SHORT_STRING); +// There are two implementations. For arrays >= 8 bytes, all +// comparisons (including the final one, which may overlap) are +// performed 8 bytes at a time. For arrays < 8 bytes, we compare a +// halfword, then a short, and then a byte. - // Check if the strings start at the same location. - cmp(str1, str2); - br(Assembler::EQ, SAME_CHARS); +void MacroAssembler::arrays_equals(Register a1, Register a2, + Register result, Register cnt1, + int elem_size, bool is_string) +{ + Label SAME, DONE, SHORT, NEXT_WORD, ONE; + Register tmp1 = rscratch1; + Register tmp2 = rscratch2; + Register cnt2 = tmp2; // cnt2 only used in array length compare + int elem_per_word = wordSize/elem_size; + int log_elem_size = exact_log2(elem_size); + int length_offset = arrayOopDesc::length_offset_in_bytes(); + int base_offset + = arrayOopDesc::base_offset_in_bytes(elem_size == 2 ? T_CHAR : T_BYTE); - // Compare longwords - { - subw(cnt, cnt, 4); // The last longword is a special case + assert(elem_size == 1 || elem_size == 2, "must be char or byte"); + assert_different_registers(a1, a2, result, cnt1, rscratch1, rscratch2); - // Move both string pointers to the last longword of their - // strings, negate the remaining count, and convert it to bytes. - lea(str1, Address(str1, cnt, Address::uxtw(1))); - lea(str2, Address(str2, cnt, Address::uxtw(1))); - sub(cnt, zr, cnt, LSL, 1); + BLOCK_COMMENT(is_string ? "string_equals {" : "array_equals {"); - // Loop, loading longwords and comparing them into rscratch2. - bind(NEXT_WORD); - ldr(tmp1, Address(str1, cnt)); - ldr(tmp2, Address(str2, cnt)); - adds(cnt, cnt, wordSize); - eor(rscratch2, tmp1, tmp2); - cbnz(rscratch2, DONE); - br(Assembler::LT, NEXT_WORD); + mov(result, false); - // Last longword. In the case where length == 4 we compare the - // same longword twice, but that's still faster than another - // conditional branch. + if (!is_string) { + // if (a==a2) + // return true; + eor(rscratch1, a1, a2); + cbz(rscratch1, SAME); + // if (a==null || a2==null) + // return false; + cbz(a1, DONE); + cbz(a2, DONE); + // if (a1.length != a2.length) + // return false; + ldrw(cnt1, Address(a1, length_offset)); + ldrw(cnt2, Address(a2, length_offset)); + eorw(tmp1, cnt1, cnt2); + cbnzw(tmp1, DONE); - ldr(tmp1, Address(str1)); - ldr(tmp2, Address(str2)); - eor(rscratch2, tmp1, tmp2); - cbz(rscratch2, SAME_CHARS); - b(DONE); + lea(a1, Address(a1, base_offset)); + lea(a2, Address(a2, base_offset)); } - bind(SHORT_STRING); - // Is the length zero? - cbz(cnt, SAME_CHARS); - - bind(SHORT_LOOP); - load_unsigned_short(tmp1, Address(post(str1, 2))); - load_unsigned_short(tmp2, Address(post(str2, 2))); - subw(tmp1, tmp1, tmp2); + // Check for short strings, i.e. smaller than wordSize. + subs(cnt1, cnt1, elem_per_word); + br(Assembler::LT, SHORT); + // Main 8 byte comparison loop. + bind(NEXT_WORD); { + ldr(tmp1, Address(post(a1, wordSize))); + ldr(tmp2, Address(post(a2, wordSize))); + subs(cnt1, cnt1, elem_per_word); + eor(tmp1, tmp1, tmp2); + cbnz(tmp1, DONE); + } br(GT, NEXT_WORD); + // Last longword. In the case where length == 4 we compare the + // same longword twice, but that's still faster than another + // conditional branch. + // cnt1 could be 0, -1, -2, -3, -4 for chars; -4 only happens when + // length == 4. + if (log_elem_size > 0) + lsl(cnt1, cnt1, log_elem_size); + ldr(tmp1, Address(a1, cnt1)); + ldr(tmp2, Address(a2, cnt1)); + eor(tmp1, tmp1, tmp2); cbnz(tmp1, DONE); - sub(cnt, cnt, 1); - cbnz(cnt, SHORT_LOOP); + b(SAME); - // Strings are equal. - bind(SAME_CHARS); + bind(SHORT); + Label TAIL03, TAIL01; + + tbz(cnt1, 2 - log_elem_size, TAIL03); // 0-7 bytes left. + { + ldrw(tmp1, Address(post(a1, 4))); + ldrw(tmp2, Address(post(a2, 4))); + eorw(tmp1, tmp1, tmp2); + cbnzw(tmp1, DONE); + } + bind(TAIL03); + tbz(cnt1, 1 - log_elem_size, TAIL01); // 0-3 bytes left. + { + ldrh(tmp1, Address(post(a1, 2))); + ldrh(tmp2, Address(post(a2, 2))); + eorw(tmp1, tmp1, tmp2); + cbnzw(tmp1, DONE); + } + bind(TAIL01); + if (elem_size == 1) { // Only needed when comparing byte arrays. + tbz(cnt1, 0, SAME); // 0-1 bytes left. + { + ldrb(tmp1, a1); + ldrb(tmp2, a2); + eorw(tmp1, tmp1, tmp2); + cbnzw(tmp1, DONE); + } + } + // Arrays are equal. + bind(SAME); mov(result, true); - // That's it + // That's it. bind(DONE); - - BLOCK_COMMENT("} string_equals"); + BLOCK_COMMENT(is_string ? "} string_equals" : "} array_equals"); } -void MacroAssembler::byte_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1) -{ - Register cnt1 = rscratch1; - Register cnt2 = rscratch2; - Register tmp2 = rscratch2; - - Label SAME, DIFFER, NEXT, TAIL07, TAIL03, TAIL01; - - int length_offset = arrayOopDesc::length_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_BYTE); - - BLOCK_COMMENT("byte_arrays_equals {"); - - // different until proven equal - mov(result, false); - - // same array? - cmp(ary1, ary2); - br(Assembler::EQ, SAME); - - // ne if either null - cbz(ary1, DIFFER); - cbz(ary2, DIFFER); - - // lengths ne? - ldrw(cnt1, Address(ary1, length_offset)); - ldrw(cnt2, Address(ary2, length_offset)); - cmp(cnt1, cnt2); - br(Assembler::NE, DIFFER); - - lea(ary1, Address(ary1, base_offset)); - lea(ary2, Address(ary2, base_offset)); - - subs(cnt1, cnt1, 8); - br(LT, TAIL07); - - BIND(NEXT); - ldr(tmp1, Address(post(ary1, 8))); - ldr(tmp2, Address(post(ary2, 8))); - subs(cnt1, cnt1, 8); - eor(tmp1, tmp1, tmp2); - cbnz(tmp1, DIFFER); - br(GE, NEXT); - - BIND(TAIL07); // 0-7 bytes left, cnt1 = #bytes left - 4 - tst(cnt1, 0b100); - br(EQ, TAIL03); - ldrw(tmp1, Address(post(ary1, 4))); - ldrw(tmp2, Address(post(ary2, 4))); - cmp(tmp1, tmp2); - br(NE, DIFFER); - - BIND(TAIL03); // 0-3 bytes left, cnt1 = #bytes left - 4 - tst(cnt1, 0b10); - br(EQ, TAIL01); - ldrh(tmp1, Address(post(ary1, 2))); - ldrh(tmp2, Address(post(ary2, 2))); - cmp(tmp1, tmp2); - br(NE, DIFFER); - BIND(TAIL01); // 0-1 byte left - tst(cnt1, 0b01); - br(EQ, SAME); - ldrb(tmp1, ary1); - ldrb(tmp2, ary2); - cmp(tmp1, tmp2); - br(NE, DIFFER); - - BIND(SAME); - mov(result, true); - BIND(DIFFER); // result already set - - BLOCK_COMMENT("} byte_arrays_equals"); -} - -// Compare char[] arrays aligned to 4 bytes -void MacroAssembler::char_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1) -{ - Register cnt1 = rscratch1; - Register cnt2 = rscratch2; - Register tmp2 = rscratch2; - - Label SAME, DIFFER, NEXT, TAIL03, TAIL01; - - int length_offset = arrayOopDesc::length_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); - - BLOCK_COMMENT("char_arrays_equals {"); - - // different until proven equal - mov(result, false); - - // same array? - cmp(ary1, ary2); - br(Assembler::EQ, SAME); - - // ne if either null - cbz(ary1, DIFFER); - cbz(ary2, DIFFER); - - // lengths ne? - ldrw(cnt1, Address(ary1, length_offset)); - ldrw(cnt2, Address(ary2, length_offset)); - cmp(cnt1, cnt2); - br(Assembler::NE, DIFFER); - - lea(ary1, Address(ary1, base_offset)); - lea(ary2, Address(ary2, base_offset)); - - subs(cnt1, cnt1, 4); - br(LT, TAIL03); - - BIND(NEXT); - ldr(tmp1, Address(post(ary1, 8))); - ldr(tmp2, Address(post(ary2, 8))); - subs(cnt1, cnt1, 4); - eor(tmp1, tmp1, tmp2); - cbnz(tmp1, DIFFER); - br(GE, NEXT); - - BIND(TAIL03); // 0-3 chars left, cnt1 = #chars left - 4 - tst(cnt1, 0b10); - br(EQ, TAIL01); - ldrw(tmp1, Address(post(ary1, 4))); - ldrw(tmp2, Address(post(ary2, 4))); - cmp(tmp1, tmp2); - br(NE, DIFFER); - BIND(TAIL01); // 0-1 chars left - tst(cnt1, 0b01); - br(EQ, SAME); - ldrh(tmp1, ary1); - ldrh(tmp2, ary2); - cmp(tmp1, tmp2); - br(NE, DIFFER); - - BIND(SAME); - mov(result, true); - BIND(DIFFER); // result already set - - BLOCK_COMMENT("} char_arrays_equals"); -} - // encode char[] to byte[] in ISO_8859_1 void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, Register result, diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp index d22c581bc41..e042b5055eb 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp @@ -1186,13 +1186,11 @@ public: void string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register result, Register tmp1); - void string_equals(Register str1, Register str2, - Register cnt, Register result, - Register tmp1); - void char_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1); - void byte_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1); + + void arrays_equals(Register a1, Register a2, + Register result, Register cnt1, + int elem_size, bool is_string); + void encode_iso_array(Register src, Register dst, Register len, Register result, FloatRegister Vtmp1, FloatRegister Vtmp2, From a30c46aa74610773458947247315459e487ec9f3 Mon Sep 17 00:00:00 2001 From: Felix Yang Date: Wed, 17 Feb 2016 20:19:24 +0800 Subject: [PATCH 046/183] 8150038: aarch64: make use of CBZ and CBNZ when comparing narrow pointer with zero Aarch64: c2 make use of CBZ and CBNZ when comparing narrow pointer with zero Reviewed-by: aph --- hotspot/src/cpu/aarch64/vm/aarch64.ad | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index e980a2332f3..8483c709564 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -14191,6 +14191,25 @@ instruct cmpP_imm0_branch(cmpOp cmp, iRegP op1, immP0 op2, label labl, rFlagsReg ins_pipe(pipe_cmp_branch); %} +instruct cmpN_imm0_branch(cmpOp cmp, iRegN op1, immN0 op2, label labl, rFlagsReg cr) %{ + match(If cmp (CmpN op1 op2)); + predicate(n->in(1)->as_Bool()->_test._test == BoolTest::ne + || n->in(1)->as_Bool()->_test._test == BoolTest::eq); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "cbw$cmp $op1, $labl" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; + if (cond == Assembler::EQ) + __ cbzw($op1$$Register, *L); + else + __ cbnzw($op1$$Register, *L); + %} + ins_pipe(pipe_cmp_branch); +%} + instruct cmpP_narrowOop_imm0_branch(cmpOp cmp, iRegN oop, immP0 zero, label labl, rFlagsReg cr) %{ match(If cmp (CmpP (DecodeN oop) zero)); predicate(n->in(1)->as_Bool()->_test._test == BoolTest::ne From 40cdd7a181d53e5a533b1a6644fdcc58a2601664 Mon Sep 17 00:00:00 2001 From: Felix Yang Date: Thu, 18 Feb 2016 21:53:24 +0800 Subject: [PATCH 047/183] 8149907: aarch64: use load/store pair instructions in call_stub Aarch64: make use of load/store pair instructions in call_stub to save space Reviewed-by: aph --- .../cpu/aarch64/vm/stubGenerator_aarch64.cpp | 94 +++++-------------- 1 file changed, 26 insertions(+), 68 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp index 64833c5ccc4..942d7bc5cb7 100644 --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp @@ -163,30 +163,20 @@ class StubGenerator: public StubCodeGenerator { sp_after_call_off = -26, d15_off = -26, - d14_off = -25, d13_off = -24, - d12_off = -23, d11_off = -22, - d10_off = -21, d9_off = -20, - d8_off = -19, r28_off = -18, - r27_off = -17, r26_off = -16, - r25_off = -15, r24_off = -14, - r23_off = -13, r22_off = -12, - r21_off = -11, r20_off = -10, - r19_off = -9, call_wrapper_off = -8, result_off = -7, result_type_off = -6, method_off = -5, entry_point_off = -4, - parameters_off = -3, parameter_size_off = -2, thread_off = -1, fp_f = 0, @@ -208,30 +198,20 @@ class StubGenerator: public StubCodeGenerator { const Address result_type (rfp, result_type_off * wordSize); const Address method (rfp, method_off * wordSize); const Address entry_point (rfp, entry_point_off * wordSize); - const Address parameters (rfp, parameters_off * wordSize); const Address parameter_size(rfp, parameter_size_off * wordSize); const Address thread (rfp, thread_off * wordSize); const Address d15_save (rfp, d15_off * wordSize); - const Address d14_save (rfp, d14_off * wordSize); const Address d13_save (rfp, d13_off * wordSize); - const Address d12_save (rfp, d12_off * wordSize); const Address d11_save (rfp, d11_off * wordSize); - const Address d10_save (rfp, d10_off * wordSize); const Address d9_save (rfp, d9_off * wordSize); - const Address d8_save (rfp, d8_off * wordSize); const Address r28_save (rfp, r28_off * wordSize); - const Address r27_save (rfp, r27_off * wordSize); const Address r26_save (rfp, r26_off * wordSize); - const Address r25_save (rfp, r25_off * wordSize); const Address r24_save (rfp, r24_off * wordSize); - const Address r23_save (rfp, r23_off * wordSize); const Address r22_save (rfp, r22_off * wordSize); - const Address r21_save (rfp, r21_off * wordSize); const Address r20_save (rfp, r20_off * wordSize); - const Address r19_save (rfp, r19_off * wordSize); // stub code @@ -254,31 +234,20 @@ class StubGenerator: public StubCodeGenerator { // rthread because we want to sanity check rthread later __ str(c_rarg7, thread); __ strw(c_rarg6, parameter_size); - __ str(c_rarg5, parameters); - __ str(c_rarg4, entry_point); - __ str(c_rarg3, method); - __ str(c_rarg2, result_type); - __ str(c_rarg1, result); - __ str(c_rarg0, call_wrapper); - __ str(r19, r19_save); - __ str(r20, r20_save); - __ str(r21, r21_save); - __ str(r22, r22_save); - __ str(r23, r23_save); - __ str(r24, r24_save); - __ str(r25, r25_save); - __ str(r26, r26_save); - __ str(r27, r27_save); - __ str(r28, r28_save); + __ stp(c_rarg4, c_rarg5, entry_point); + __ stp(c_rarg2, c_rarg3, result_type); + __ stp(c_rarg0, c_rarg1, call_wrapper); - __ strd(v8, d8_save); - __ strd(v9, d9_save); - __ strd(v10, d10_save); - __ strd(v11, d11_save); - __ strd(v12, d12_save); - __ strd(v13, d13_save); - __ strd(v14, d14_save); - __ strd(v15, d15_save); + __ stp(r20, r19, r20_save); + __ stp(r22, r21, r22_save); + __ stp(r24, r23, r24_save); + __ stp(r26, r25, r26_save); + __ stp(r28, r27, r28_save); + + __ stpd(v9, v8, d9_save); + __ stpd(v11, v10, d11_save); + __ stpd(v13, v12, d13_save); + __ stpd(v15, v14, d15_save); // install Java thread in global register now we have saved // whatever value it held @@ -385,33 +354,22 @@ class StubGenerator: public StubCodeGenerator { #endif // restore callee-save registers - __ ldrd(v15, d15_save); - __ ldrd(v14, d14_save); - __ ldrd(v13, d13_save); - __ ldrd(v12, d12_save); - __ ldrd(v11, d11_save); - __ ldrd(v10, d10_save); - __ ldrd(v9, d9_save); - __ ldrd(v8, d8_save); + __ ldpd(v15, v14, d15_save); + __ ldpd(v13, v12, d13_save); + __ ldpd(v11, v10, d11_save); + __ ldpd(v9, v8, d9_save); - __ ldr(r28, r28_save); - __ ldr(r27, r27_save); - __ ldr(r26, r26_save); - __ ldr(r25, r25_save); - __ ldr(r24, r24_save); - __ ldr(r23, r23_save); - __ ldr(r22, r22_save); - __ ldr(r21, r21_save); - __ ldr(r20, r20_save); - __ ldr(r19, r19_save); - __ ldr(c_rarg0, call_wrapper); - __ ldr(c_rarg1, result); + __ ldp(r28, r27, r28_save); + __ ldp(r26, r25, r26_save); + __ ldp(r24, r23, r24_save); + __ ldp(r22, r21, r22_save); + __ ldp(r20, r19, r20_save); + + __ ldp(c_rarg0, c_rarg1, call_wrapper); __ ldrw(c_rarg2, result_type); __ ldr(c_rarg3, method); - __ ldr(c_rarg4, entry_point); - __ ldr(c_rarg5, parameters); - __ ldr(c_rarg6, parameter_size); - __ ldr(c_rarg7, thread); + __ ldp(c_rarg4, c_rarg5, entry_point); + __ ldp(c_rarg6, c_rarg7, parameter_size); #ifndef PRODUCT // tell the simulator we are about to end Java execution From 35a916a2a186a093ef4c4b759edc1164793ef82a Mon Sep 17 00:00:00 2001 From: Andreas Eriksson Date: Thu, 18 Feb 2016 16:15:28 +0100 Subject: [PATCH 048/183] 8149743: JVM crash after debugger hotswap with lambdas Reviewed-by: sspitsyn, coleenp, dcubed --- hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp index 8823e6670a6..6b176ec1f70 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, 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 @@ -3940,6 +3940,10 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass, scratch_class->set_methods(_old_methods); // To prevent potential GCing of the old methods, // and to be able to undo operation easily. + Array* old_ordering = the_class->method_ordering(); + the_class->set_method_ordering(scratch_class->method_ordering()); + scratch_class->set_method_ordering(old_ordering); + ConstantPool* old_constants = the_class->constants(); the_class->set_constants(scratch_class->constants()); scratch_class->set_constants(old_constants); // See the previous comment. From 717ad7019c3aae78f4336c22fa2362f00dd1c763 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Thu, 18 Feb 2016 22:11:29 +0300 Subject: [PATCH 049/183] 8038139: AudioInputStream.getFrameLength() returns wrong value for floating-point WAV Reviewed-by: prr, amenkov --- .../com/sun/media/sound/AiffFileReader.java | 75 ++----- .../com/sun/media/sound/AiffFileWriter.java | 37 +--- .../media/sound/WaveExtensibleFileReader.java | 9 +- .../sun/media/sound/WaveFloatFileReader.java | 9 +- .../FrameLengthAfterConversion.java | 209 ++++++++++++++++++ 5 files changed, 244 insertions(+), 95 deletions(-) create mode 100644 jdk/test/javax/sound/sampled/AudioInputStream/FrameLengthAfterConversion.java diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileReader.java index 8c9dc3c78be..c0ac8bf6d40 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,11 +26,11 @@ package com.sun.media.sound; import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFileFormat.Type; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; @@ -49,11 +49,6 @@ public final class AiffFileReader extends SunFileReader { throws UnsupportedAudioFileException, IOException { DataInputStream dis = new DataInputStream(stream); - // assumes a stream at the beginning of the file which has already - // passed the magic number test... - // leaves the input stream at the beginning of the audio data - int fileRead = 0; - int dataLength = 0; AudioFormat format = null; // Read the magic number @@ -65,9 +60,9 @@ public final class AiffFileReader extends SunFileReader { throw new UnsupportedAudioFileException("not an AIFF file"); } + int frameLength = 0; int length = dis.readInt(); int iffType = dis.readInt(); - fileRead += 12; int totallength; if(length <= 0 ) { @@ -91,7 +86,6 @@ public final class AiffFileReader extends SunFileReader { // Read the chunk name int chunkName = dis.readInt(); int chunkLen = dis.readInt(); - fileRead += 8; int chunkRead = 0; @@ -112,7 +106,13 @@ public final class AiffFileReader extends SunFileReader { if (channels <= 0) { throw new UnsupportedAudioFileException("Invalid number of channels"); } - dis.readInt(); // numSampleFrames + frameLength = dis.readInt(); // numSampleFrames + if (frameLength < 0) { + // AiffFileFormat uses int, unlike AIS which uses long + //TODO this (negative) value should be passed as long to AIS + frameLength = AudioSystem.NOT_SPECIFIED; + } + int sampleSizeInBits = dis.readUnsignedShort(); if (sampleSizeInBits < 1 || sampleSizeInBits > 32) { throw new UnsupportedAudioFileException("Invalid AIFF/COMM sampleSize"); @@ -149,38 +149,17 @@ public final class AiffFileReader extends SunFileReader { break; case AiffFileFormat.SSND_MAGIC: // Data chunk. - // we are getting *weird* numbers for chunkLen sometimes; - // this really should be the size of the data chunk.... - int dataOffset = dis.readInt(); - int blocksize = dis.readInt(); + int dataOffset = dis.readInt(); // for now unused in javasound + int blocksize = dis.readInt(); // for now unused in javasound chunkRead += 8; - - // okay, now we are done reading the header. we need to set the size - // of the data segment. we know that sometimes the value we get for - // the chunksize is absurd. this is the best i can think of:if the - // value seems okay, use it. otherwise, we get our value of - // length by assuming that everything left is the data segment; - // its length should be our original length (for all AIFF data chunks) - // minus what we've read so far. - // $$kk: we should be able to get length for the data chunk right after - // we find "SSND." however, some aiff files give *weird* numbers. what - // is going on?? - - if (chunkLen < length) { - dataLength = chunkLen - chunkRead; - } else { - // $$kk: 11.03.98: this seems dangerous! - dataLength = length - (fileRead + chunkRead); - } ssndFound = true; break; } // switch - fileRead += chunkRead; // skip the remainder of this chunk if (!ssndFound) { int toSkip = chunkLen - chunkRead; if (toSkip > 0) { - fileRead += dis.skipBytes(toSkip); + dis.skipBytes(toSkip); } } } // while @@ -188,36 +167,12 @@ public final class AiffFileReader extends SunFileReader { if (format == null) { throw new UnsupportedAudioFileException("missing COMM chunk"); } - AudioFileFormat.Type type = aifc?AudioFileFormat.Type.AIFC:AudioFileFormat.Type.AIFF; + Type type = aifc ? Type.AIFC : Type.AIFF; - return new AiffFileFormat(type, totallength, format, dataLength / format.getFrameSize()); + return new AiffFileFormat(type, totallength, format, frameLength); } // HELPER METHODS - /** write_ieee_extended(DataOutputStream dos, double f) throws IOException { - * Extended precision IEEE floating-point conversion routine. - * @argument DataOutputStream - * @argument double - * @return void - * @exception IOException - */ - private void write_ieee_extended(DataOutputStream dos, double f) throws IOException { - - int exponent = 16398; - double highMantissa = f; - - // For now write the integer portion of f - // $$jb: 03.30.99: stay in synch with JMF on this!!!! - while (highMantissa < 44000) { - highMantissa *= 2; - exponent--; - } - dos.writeShort(exponent); - dos.writeInt( ((int) highMantissa) << 16); - dos.writeInt(0); // low Mantissa - } - - /** * read_ieee_extended * Extended precision IEEE floating-point conversion routine. diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java index 0a4788df804..9b5ebac2f6b 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java @@ -59,7 +59,6 @@ public final class AiffFileWriter extends SunFileWriter { super(new AudioFileFormat.Type[]{AudioFileFormat.Type.AIFF}); } - // METHODS TO IMPLEMENT AudioFileWriter @Override @@ -83,7 +82,6 @@ public final class AiffFileWriter extends SunFileWriter { return new AudioFileFormat.Type[0]; } - @Override public int write(AudioInputStream stream, AudioFileFormat.Type fileType, OutputStream out) throws IOException { Objects.requireNonNull(stream); @@ -102,11 +100,9 @@ public final class AiffFileWriter extends SunFileWriter { throw new IOException("stream length not specified"); } - int bytesWritten = writeAiffFile(stream, aiffFileFormat, out); - return bytesWritten; + return writeAiffFile(stream, aiffFileFormat, out); } - @Override public int write(AudioInputStream stream, AudioFileFormat.Type fileType, File out) throws IOException { Objects.requireNonNull(stream); @@ -129,12 +125,15 @@ public final class AiffFileWriter extends SunFileWriter { // $$kk: 10.22.99: jan: please either implement this or throw an exception! // $$fb: 2001-07-13: done. Fixes Bug 4479981 - int ssndBlockSize = (aiffFileFormat.getFormat().getChannels() * aiffFileFormat.getFormat().getSampleSizeInBits()); + int channels = aiffFileFormat.getFormat().getChannels(); + int sampleSize = aiffFileFormat.getFormat().getSampleSizeInBits(); + int ssndBlockSize = channels * ((sampleSize + 7) / 8); int aiffLength=bytesWritten; int ssndChunkSize=aiffLength-aiffFileFormat.getHeaderSize()+16; long dataSize=ssndChunkSize-16; - int numFrames=(int) (dataSize*8/ssndBlockSize); + //TODO possibly incorrect round + int numFrames = (int) (dataSize / ssndBlockSize); RandomAccessFile raf=new RandomAccessFile(out, "rw"); // skip FORM magic @@ -173,12 +172,7 @@ public final class AiffFileWriter extends SunFileWriter { AudioFormat streamFormat = stream.getFormat(); AudioFormat.Encoding streamEncoding = streamFormat.getEncoding(); - - float sampleRate; int sampleSizeInBits; - int channels; - int frameSize; - float frameRate; int fileSize; boolean convert8to16 = false; @@ -235,7 +229,6 @@ public final class AiffFileWriter extends SunFileWriter { return fileFormat; } - private int writeAiffFile(InputStream in, AiffFileFormat aiffFileFormat, OutputStream out) throws IOException { int bytesRead = 0; @@ -275,25 +268,20 @@ public final class AiffFileWriter extends SunFileWriter { AudioFormat.Encoding encoding = null; //$$fb a little bit nicer handling of constants - - //int headerSize = 54; int headerSize = aiffFileFormat.getHeaderSize(); - //int fverChunkSize = 0; int fverChunkSize = aiffFileFormat.getFverChunkSize(); - //int commChunkSize = 26; int commChunkSize = aiffFileFormat.getCommChunkSize(); int aiffLength = -1; int ssndChunkSize = -1; - //int ssndOffset = headerSize - 16; int ssndOffset = aiffFileFormat.getSsndChunkOffset(); short channels = (short) format.getChannels(); short sampleSize = (short) format.getSampleSizeInBits(); - int ssndBlockSize = (channels * sampleSize); - int numFrames = aiffFileFormat.getFrameLength(); - long dataSize = -1; + int ssndBlockSize = channels * ((sampleSize + 7) / 8); + int numFrames = aiffFileFormat.getFrameLength(); + long dataSize = -1; if( numFrames != AudioSystem.NOT_SPECIFIED) { - dataSize = (long) numFrames * ssndBlockSize / 8; + dataSize = (long) numFrames * ssndBlockSize; ssndChunkSize = (int)dataSize + 16; aiffLength = (int)dataSize+headerSize; } @@ -403,9 +391,6 @@ public final class AiffFileWriter extends SunFileWriter { } - - - // HELPER METHODS private static final int DOUBLE_MANTISSA_LENGTH = 52; @@ -452,6 +437,4 @@ public final class AiffFileWriter extends SunFileWriter { dos.writeShort(extendedBits79To64); dos.writeLong(extendedBits63To0); } - - } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java index 240c6d27c58..9085c58b530 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java @@ -255,16 +255,17 @@ public final class WaveExtensibleFileReader extends SunFileReader { public AudioInputStream getAudioInputStream(final InputStream stream) throws UnsupportedAudioFileException, IOException { - AudioFileFormat format = getAudioFileFormat(stream); + final AudioFileFormat format = getAudioFileFormat(stream); // we've got everything, the stream is supported and it is at the // beginning of the header, so find the data chunk again and return an // AudioInputStream - RIFFReader riffiterator = new RIFFReader(stream); + final RIFFReader riffiterator = new RIFFReader(stream); while (riffiterator.hasNextChunk()) { RIFFReader chunk = riffiterator.nextChunk(); if (chunk.getFormat().equals("data")) { - return new AudioInputStream(chunk, format.getFormat(), chunk - .getSize()); + final AudioFormat af = format.getFormat(); + final long length = chunk.getSize() / af.getFrameSize(); + return new AudioInputStream(chunk, af, length); } } throw new UnsupportedAudioFileException(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java index afecd0e34be..6639cf040e8 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java @@ -95,16 +95,17 @@ public final class WaveFloatFileReader extends SunFileReader { public AudioInputStream getAudioInputStream(final InputStream stream) throws UnsupportedAudioFileException, IOException { - AudioFileFormat format = getAudioFileFormat(stream); + final AudioFileFormat format = getAudioFileFormat(stream); // we've got everything, the stream is supported and it is at the // beginning of the header, so find the data chunk again and return an // AudioInputStream - RIFFReader riffiterator = new RIFFReader(stream); + final RIFFReader riffiterator = new RIFFReader(stream); while (riffiterator.hasNextChunk()) { RIFFReader chunk = riffiterator.nextChunk(); if (chunk.getFormat().equals("data")) { - return new AudioInputStream(chunk, format.getFormat(), - chunk.getSize()); + final AudioFormat af = format.getFormat(); + final long length = chunk.getSize() / af.getFrameSize(); + return new AudioInputStream(chunk, af, length); } } throw new UnsupportedAudioFileException(); diff --git a/jdk/test/javax/sound/sampled/AudioInputStream/FrameLengthAfterConversion.java b/jdk/test/javax/sound/sampled/AudioInputStream/FrameLengthAfterConversion.java new file mode 100644 index 00000000000..e32e7723db5 --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioInputStream/FrameLengthAfterConversion.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2016, 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.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.spi.AudioFileWriter; +import javax.sound.sampled.spi.FormatConversionProvider; + +import static java.util.ServiceLoader.load; +import static javax.sound.sampled.AudioFileFormat.Type.AIFC; +import static javax.sound.sampled.AudioFileFormat.Type.AIFF; +import static javax.sound.sampled.AudioFileFormat.Type.AU; +import static javax.sound.sampled.AudioFileFormat.Type.SND; +import static javax.sound.sampled.AudioFileFormat.Type.WAVE; +import static javax.sound.sampled.AudioSystem.NOT_SPECIFIED; + +/** + * @test + * @bug 8038139 + */ +public final class FrameLengthAfterConversion { + + /** + * We will try to use all formats, in this case all our providers will be + * covered by supported/unsupported formats. + */ + private static final List formats = new ArrayList<>(23000); + + private static final AudioFormat.Encoding[] encodings = { + AudioFormat.Encoding.ALAW, AudioFormat.Encoding.ULAW, + AudioFormat.Encoding.PCM_SIGNED, AudioFormat.Encoding.PCM_UNSIGNED, + AudioFormat.Encoding.PCM_FLOAT, new AudioFormat.Encoding("Test") + }; + + private static final int[] sampleBits = { + 1, 4, 8, 11, 16, 20, 24, 32 + }; + + private static final int[] channels = { + 1, 2, 3, 4, 5 + }; + + private static final AudioFileFormat.Type[] types = { + WAVE, AU, AIFF, AIFC, SND, + new AudioFileFormat.Type("TestName", "TestExt") + }; + + private static final int FRAME_LENGTH = 10; + + static { + for (final int sampleSize : sampleBits) { + for (final int channel : channels) { + for (final AudioFormat.Encoding enc : encodings) { + final int frameSize = ((sampleSize + 7) / 8) * channel; + formats.add(new AudioFormat(enc, 44100, sampleSize, channel, + frameSize, 44100, true)); + formats.add(new AudioFormat(enc, 44100, sampleSize, channel, + frameSize, 44100, false)); + } + } + } + } + + public static void main(final String[] args) { + for (final FormatConversionProvider fcp : load( + FormatConversionProvider.class)) { + System.out.println("fcp = " + fcp); + for (final AudioFormat from : formats) { + for (final AudioFormat to : formats) { + testAfterConversion(fcp, to, getStream(from, true)); + } + } + } + + for (final AudioFileWriter afw : load(AudioFileWriter.class)) { + System.out.println("afw = " + afw); + for (final AudioFileFormat.Type type : types) { + for (final AudioFormat from : formats) { + testAfterSaveToStream(afw, type, getStream(from, true)); + } + } + } + + for (final AudioFileWriter afw : load(AudioFileWriter.class)) { + System.out.println("afw = " + afw); + for (final AudioFileFormat.Type type : types) { + for (final AudioFormat from : formats) { + testAfterSaveToFile(afw, type, getStream(from, true)); + } + } + } + + for (final AudioFileWriter afw : load(AudioFileWriter.class)) { + System.out.println("afw = " + afw); + for (final AudioFileFormat.Type type : types) { + for (final AudioFormat from : formats) { + testAfterSaveToFile(afw, type, getStream(from, false)); + } + } + } + } + + /** + * Verifies the frame length after the stream was saved/read to/from + * stream. + */ + private static void testAfterSaveToStream(final AudioFileWriter afw, + final AudioFileFormat.Type type, + final AudioInputStream ais) { + try { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + afw.write(ais, type, out); + final InputStream input = new ByteArrayInputStream( + out.toByteArray()); + validate(AudioSystem.getAudioInputStream(input).getFrameLength()); + } catch (IllegalArgumentException | UnsupportedAudioFileException + | IOException ignored) { + } + } + + /** + * Verifies the frame length after the stream was saved/read to/from file. + */ + private static void testAfterSaveToFile(final AudioFileWriter afw, + final AudioFileFormat.Type type, + AudioInputStream ais) { + try { + final File temp = File.createTempFile("sound", ".tmp"); + temp.deleteOnExit(); + afw.write(ais, type, temp); + ais = AudioSystem.getAudioInputStream(temp); + final long frameLength = ais.getFrameLength(); + ais.close(); + temp.delete(); + validate(frameLength); + } catch (IllegalArgumentException | UnsupportedAudioFileException + | IOException ignored) { + } + } + + /** + * Verifies the frame length after the stream was converted to other + * stream. + * + * @see FormatConversionProvider#getAudioInputStream(AudioFormat, + * AudioInputStream) + */ + private static void testAfterConversion(final FormatConversionProvider fcp, + final AudioFormat to, + final AudioInputStream ais) { + if (fcp.isConversionSupported(to, ais.getFormat())) { + validate(fcp.getAudioInputStream(to, ais).getFrameLength()); + } + } + + /** + * Throws an exception if the frameLength is specified and is not equal to + * the gold value. + */ + private static void validate(final long frameLength) { + if (frameLength != FRAME_LENGTH) { + System.err.println("Expected: " + FRAME_LENGTH); + System.err.println("Actual: " + frameLength); + throw new RuntimeException(); + } + } + + private static AudioInputStream getStream(final AudioFormat format, + final boolean frameLength) { + final int dataSize = FRAME_LENGTH * format.getFrameSize(); + final InputStream in = new ByteArrayInputStream(new byte[dataSize]); + if (frameLength) { + return new AudioInputStream(in, format, FRAME_LENGTH); + } else { + return new AudioInputStream(in, format, NOT_SPECIFIED); + } + } +} From d466ce4948fd6b5099da43453621a1437a40fc18 Mon Sep 17 00:00:00 2001 From: Felix Yang Date: Fri, 19 Feb 2016 17:12:14 +0800 Subject: [PATCH 050/183] 8150229: aarch64: pipeline class for several instructions is not set correctly Aarch64: c2 fix pipeline class for several instructions. Reviewed-by: aph --- hotspot/src/cpu/aarch64/vm/aarch64.ad | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index 8483c709564..acc65080e2f 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -13281,7 +13281,7 @@ instruct MoveF2I_reg_reg(iRegINoSp dst, vRegF src) %{ __ fmovs($dst$$Register, as_FloatRegister($src$$reg)); %} - ins_pipe(pipe_class_memory); + ins_pipe(fp_f2i); %} @@ -13299,7 +13299,7 @@ instruct MoveI2F_reg_reg(vRegF dst, iRegI src) %{ __ fmovs(as_FloatRegister($dst$$reg), $src$$Register); %} - ins_pipe(pipe_class_memory); + ins_pipe(fp_i2f); %} @@ -13317,7 +13317,7 @@ instruct MoveD2L_reg_reg(iRegLNoSp dst, vRegD src) %{ __ fmovd($dst$$Register, as_FloatRegister($src$$reg)); %} - ins_pipe(pipe_class_memory); + ins_pipe(fp_d2l); %} @@ -13335,7 +13335,7 @@ instruct MoveL2D_reg_reg(vRegD dst, iRegL src) %{ __ fmovd(as_FloatRegister($dst$$reg), $src$$Register); %} - ins_pipe(pipe_class_memory); + ins_pipe(fp_l2d); %} @@ -16502,7 +16502,7 @@ instruct vsll2I(vecD dst, vecD src, vecX shift) %{ as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); %} - ins_pipe(vshift64_imm); + ins_pipe(vshift64); %} instruct vsll4I(vecX dst, vecX src, vecX shift) %{ @@ -16516,7 +16516,7 @@ instruct vsll4I(vecX dst, vecX src, vecX shift) %{ as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); %} - ins_pipe(vshift128_imm); + ins_pipe(vshift128); %} instruct vsrl2I(vecD dst, vecD src, vecX shift) %{ @@ -16529,7 +16529,7 @@ instruct vsrl2I(vecD dst, vecD src, vecX shift) %{ as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); %} - ins_pipe(vshift64_imm); + ins_pipe(vshift64); %} instruct vsrl4I(vecX dst, vecX src, vecX shift) %{ @@ -16542,7 +16542,7 @@ instruct vsrl4I(vecX dst, vecX src, vecX shift) %{ as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); %} - ins_pipe(vshift128_imm); + ins_pipe(vshift128); %} instruct vsll2I_imm(vecD dst, vecD src, immI shift) %{ @@ -16660,7 +16660,7 @@ instruct vsll2L_imm(vecX dst, vecX src, immI shift) %{ as_FloatRegister($src$$reg), (int)$shift$$constant & 63); %} - ins_pipe(vshift128); + ins_pipe(vshift128_imm); %} instruct vsra2L_imm(vecX dst, vecX src, immI shift) %{ From 516438f368d53be93596baaf2d1f35d26770934c Mon Sep 17 00:00:00 2001 From: Konstantin Shefov Date: Sat, 20 Feb 2016 11:43:13 +0300 Subject: [PATCH 051/183] 8141616: Add new methods to the java Whitebox API Reviewed-by: kvn, dpochepk --- test/lib/sun/hotspot/WhiteBox.java | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/lib/sun/hotspot/WhiteBox.java b/test/lib/sun/hotspot/WhiteBox.java index 6b7863ad938..9964831c3c9 100644 --- a/test/lib/sun/hotspot/WhiteBox.java +++ b/test/lib/sun/hotspot/WhiteBox.java @@ -119,6 +119,28 @@ public class WhiteBox { return getConstantPool0(aClass); } + private native int getConstantPoolCacheIndexTag0(); + public int getConstantPoolCacheIndexTag() { + return getConstantPoolCacheIndexTag0(); + } + + private native int getConstantPoolCacheLength0(Class aClass); + public int getConstantPoolCacheLength(Class aClass) { + Objects.requireNonNull(aClass); + return getConstantPoolCacheLength0(aClass); + } + + private native int remapInstructionOperandFromCPCache0(Class aClass, int index); + public int remapInstructionOperandFromCPCache(Class aClass, int index) { + Objects.requireNonNull(aClass); + return remapInstructionOperandFromCPCache0(aClass, index); + } + + private native int encodeConstantPoolIndyIndex0(int index); + public int encodeConstantPoolIndyIndex(int index) { + return encodeConstantPoolIndyIndex0(index); + } + // JVMTI private native void addToBootstrapClassLoaderSearch0(String segment); public void addToBootstrapClassLoaderSearch(String segment){ From a06164b8d9ce74075aa0a1b6c460e502f472ab97 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 23 Feb 2016 10:22:40 +0530 Subject: [PATCH 052/183] 8150233: Missing copyright headers in XSurfaceData/ExtendedKeyCodes Reviewed-by: prr --- .../classes/sun/awt/ExtendedKeyCodes.java | 24 +++++++++++++++++++ .../classes/sun/java2d/x11/XSurfaceData.java | 24 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/jdk/src/java.desktop/share/classes/sun/awt/ExtendedKeyCodes.java b/jdk/src/java.desktop/share/classes/sun/awt/ExtendedKeyCodes.java index 1e054b9de81..c034dbebd44 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/ExtendedKeyCodes.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/ExtendedKeyCodes.java @@ -1,3 +1,27 @@ +/* + * Copyright (c) 2009, 2016, 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 sun.awt; import java.util.Collections; diff --git a/jdk/src/java.desktop/unix/classes/sun/java2d/x11/XSurfaceData.java b/jdk/src/java.desktop/unix/classes/sun/java2d/x11/XSurfaceData.java index 8e71a80a0e9..dbae176dd7e 100644 --- a/jdk/src/java.desktop/unix/classes/sun/java2d/x11/XSurfaceData.java +++ b/jdk/src/java.desktop/unix/classes/sun/java2d/x11/XSurfaceData.java @@ -1,3 +1,27 @@ +/* + * Copyright (c) 2010, 2016, 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 sun.java2d.x11; import java.awt.image.*; From 43cef7fa52bf08269e2dbd60408f4b0f6d6547b1 Mon Sep 17 00:00:00 2001 From: Manajit Halder Date: Tue, 23 Feb 2016 10:24:29 +0530 Subject: [PATCH 053/183] 8147834: [macosx] KeyEvents for function keys F17, F18, F19 return keyCode 0 Reviewed-by: serb, aniyogi --- .../macosx/native/libawt_lwawt/awt/AWTEvent.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m index 07bb7fab938..9b8e370a938 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m @@ -134,7 +134,7 @@ const keyTable[] = {0x3D, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, {0x3E, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, {0x3F, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, // the 'fn' key on PowerBooks - {0x40, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, + {0x40, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F17}, {0x41, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_DECIMAL}, {0x42, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, {0x43, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_MULTIPLY}, @@ -149,8 +149,8 @@ const keyTable[] = {0x4C, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_ENTER}, {0x4D, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, {0x4E, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_SUBTRACT}, - {0x4F, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, - {0x50, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, + {0x4F, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F18}, + {0x50, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F19}, {0x51, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_EQUALS}, {0x52, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD0}, {0x53, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD1}, @@ -160,7 +160,7 @@ const keyTable[] = {0x57, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD5}, {0x58, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD6}, {0x59, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD7}, - {0x5A, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, + {0x5A, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F20}, {0x5B, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD8}, {0x5C, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD9}, {0x5D, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_BACK_SLASH}, // This is a combo yen/backslash on JIS keyboards. From 1036ce73ea11c37337c2d84c9fd6ae60e07df021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Bourg=C3=A8s?= Date: Tue, 23 Feb 2016 22:07:27 +0100 Subject: [PATCH 054/183] 8148886: SEGV in sun.java2d.marlin.Renderer._endRendering Handle reentrancy in both AAShapePipe and MarlinRenderingEngine using new sun.java2d.ReentrantContextProvider implementations Reviewed-by: flar, prr --- .../classes/sun/java2d/ReentrantContext.java | 43 ++++ .../sun/java2d/ReentrantContextProvider.java | 169 +++++++++++++++ .../java2d/ReentrantContextProviderCLQ.java | 89 ++++++++ .../java2d/ReentrantContextProviderTL.java | 123 +++++++++++ .../sun/java2d/marlin/ByteArrayCache.java | 9 +- .../sun/java2d/marlin/FloatArrayCache.java | 9 +- .../sun/java2d/marlin/IntArrayCache.java | 9 +- .../sun/java2d/marlin/MarlinCache.java | 6 +- .../java2d/marlin/MarlinRenderingEngine.java | 76 +++---- .../sun/java2d/marlin/RendererContext.java | 31 +-- .../classes/sun/java2d/marlin/Version.java | 4 +- .../classes/sun/java2d/pipe/AAShapePipe.java | 141 ++++++------ .../sun/java2d/marlin/CrashPaintTest.java | 205 ++++++++++++++++++ 13 files changed, 767 insertions(+), 147 deletions(-) create mode 100644 jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContext.java create mode 100644 jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProvider.java create mode 100644 jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderCLQ.java create mode 100644 jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderTL.java create mode 100644 jdk/test/sun/java2d/marlin/CrashPaintTest.java diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContext.java b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContext.java new file mode 100644 index 00000000000..fc067b0070d --- /dev/null +++ b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContext.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, 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 sun.java2d; + +import java.lang.ref.Reference; + +/** + * ReentrantContext is a base class to hold thread-local data supporting + * reentrancy in either a ThreadLocal or a ConcurrentLinkedQueue + * + * @see ReentrantContextProvider + */ +public class ReentrantContext { + // usage stored as a byte + byte usage = ReentrantContextProvider.USAGE_TL_INACTIVE; + /* + * Reference to this instance (hard, soft or weak). + * @see ReentrantContextProvider#refType + */ + Reference reference = null; +} diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProvider.java b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProvider.java new file mode 100644 index 00000000000..92132aabcc4 --- /dev/null +++ b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProvider.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2016, 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 sun.java2d; + +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; + +/** + * This abstract ReentrantContextProvider helper class manages the creation, + * storage, and retrieval of concrete ReentrantContext instances which can be + * subclassed to hold cached contextual data. + * + * It supports reentrancy as every call to acquire() provides a new unique context + * instance that must later be returned for reuse by a call to release(ctx) + * (typically in a try/finally block). + * + * It has a couple of abstract implementations which store references in a queue + * and/or thread-local storage. + * The Providers can be configured to hold ReentrantContext instances in memory + * using hard, soft or weak references. + * + * The acquire() and release() methods are used to retrieve and return the contexts. + * + * The {@code newContext()} method remains abstract in all implementations and + * must be provided by the module to create a new subclass of ReentrantContext + * with the appropriate contextual data in it. + * + * Sample Usage: + * - create a subclass ReentrantContextImpl to hold the thread state: + * + * static final class ReentrantContextImpl extends ReentrantContext { + * // specific cached data + * } + * + * - create the appropriate ReentrantContextProvider: + * + * private static final ReentrantContextProvider contextProvider = + * new ReentrantContextProviderTL(ReentrantContextProvider.REF_WEAK) + * { + * @Override + * protected ReentrantContextImpl newContext() { + * return new ReentrantContextImpl(); + * } + * }; + * ... + * void someMethod() { + * ReentrantContextImpl ctx = contextProvider.acquire(); + * try { + * // use the context + * } finally { + * contextProvider.release(ctx); + * } + * } + * + * @param ReentrantContext subclass + * + * @see ReentrantContext + */ +public abstract class ReentrantContextProvider +{ + // thread-local storage: inactive + static final byte USAGE_TL_INACTIVE = 0; + // thread-local storage: in use + static final byte USAGE_TL_IN_USE = 1; + // CLQ storage + static final byte USAGE_CLQ = 2; + + // hard reference + public static final int REF_HARD = 0; + // soft reference + public static final int REF_SOFT = 1; + // weak reference + public static final int REF_WEAK = 2; + + /* members */ + // internal reference type + private final int refType; + + /** + * Create a new ReentrantContext provider using the given reference type + * among hard, soft or weak + * + * @param refType reference type + */ + protected ReentrantContextProvider(final int refType) { + this.refType = refType; + } + + /** + * Create a new ReentrantContext instance + * + * @return new ReentrantContext instance + */ + protected abstract K newContext(); + + /** + * Give a ReentrantContext instance for the current thread + * + * @return ReentrantContext instance + */ + public abstract K acquire(); + + /** + * Restore the given ReentrantContext instance for reuse + * + * @param ctx ReentrantContext instance + */ + public abstract void release(K ctx); + + @SuppressWarnings("unchecked") + protected final Reference getOrCreateReference(final K ctx) { + if (ctx.reference == null) { + // Create the reference: + switch (refType) { + case REF_HARD: + ctx.reference = new HardReference(ctx); + break; + case REF_SOFT: + ctx.reference = new SoftReference(ctx); + break; + default: + case REF_WEAK: + ctx.reference = new WeakReference(ctx); + break; + } + } + return (Reference) ctx.reference; + } + + /* Missing HardReference implementation */ + static final class HardReference extends WeakReference { + // kept strong reference: + private final V strongRef; + + HardReference(final V referent) { + // no referent needed for the parent WeakReference: + super(null); + this.strongRef = referent; + } + + @Override + public V get() { + return strongRef; + } + } +} diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderCLQ.java b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderCLQ.java new file mode 100644 index 00000000000..22978cef888 --- /dev/null +++ b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderCLQ.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2016, 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 sun.java2d; + +import java.lang.ref.Reference; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * This ReentrantContextProvider implementation uses one ConcurrentLinkedQueue + * to store all ReentrantContext instances (thread and its child contexts) + * + * Note: this implementation keeps less contexts in memory depending on the + * concurrent active threads in contrary to a ThreadLocal provider. However, + * it is slower in highly concurrent workloads. + * + * @param ReentrantContext subclass + */ +public abstract class ReentrantContextProviderCLQ + extends ReentrantContextProvider +{ + // ReentrantContext queue to store all contexts + private final ConcurrentLinkedQueue> ctxQueue + = new ConcurrentLinkedQueue>(); + + /** + * Create a new ReentrantContext provider using the given reference type + * among hard, soft or weak based using a ConcurrentLinkedQueue storage + * + * @param refType reference type + */ + public ReentrantContextProviderCLQ(final int refType) { + super(refType); + } + + /** + * Give a ReentrantContext instance for the current thread + * + * @return ReentrantContext instance + */ + @Override + public final K acquire() { + K ctx = null; + // Drain queue if all referent are null: + Reference ref = null; + while ((ctx == null) && ((ref = ctxQueue.poll()) != null)) { + ctx = ref.get(); + } + if (ctx == null) { + // create a new ReentrantContext if none is available + ctx = newContext(); + ctx.usage = USAGE_CLQ; + } + return ctx; + } + + /** + * Restore the given ReentrantContext instance for reuse + * + * @param ctx ReentrantContext instance + */ + @Override + public final void release(final K ctx) { + if (ctx.usage == USAGE_CLQ) { + ctxQueue.offer(getOrCreateReference(ctx)); + } + } +} diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderTL.java b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderTL.java new file mode 100644 index 00000000000..14dcb84d6d5 --- /dev/null +++ b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderTL.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2016, 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 sun.java2d; + +import java.lang.ref.Reference; + +/** +* This ReentrantContextProvider implementation uses a ThreadLocal to hold + * the first ReentrantContext per thread and a ReentrantContextProviderCLQ to + * store child ReentrantContext instances needed during recursion. + * + * Note: this implementation may keep up to one context in memory per thread. + * Child contexts for recursive uses are stored in the queue using a WEAK + * reference by default unless specified in the 2 argument constructor. + * + * @param ReentrantContext subclass + */ +public abstract class ReentrantContextProviderTL + extends ReentrantContextProvider +{ + // Thread-local storage: + private final ThreadLocal> ctxTL + = new ThreadLocal>(); + + // ReentrantContext CLQ provider for child contexts: + private final ReentrantContextProviderCLQ ctxProviderCLQ; + + /** + * Create a new ReentrantContext provider using the given reference type + * among hard, soft or weak. + * It uses weak reference for the child contexts. + * + * @param refType reference type + */ + public ReentrantContextProviderTL(final int refType) { + this(refType, REF_WEAK); + } + + /** + * Create a new ReentrantContext provider using the given reference types + * among hard, soft or weak + * + * @param refTypeTL reference type used by ThreadLocal + * @param refTypeCLQ reference type used by ReentrantContextProviderCLQ + */ + public ReentrantContextProviderTL(final int refTypeTL, final int refTypeCLQ) + { + super(refTypeTL); + + final ReentrantContextProviderTL parent = this; + + this.ctxProviderCLQ = new ReentrantContextProviderCLQ(refTypeCLQ) { + @Override + protected K newContext() { + return parent.newContext(); + } + }; + } + + /** + * Give a ReentrantContext instance for the current thread + * + * @return ReentrantContext instance + */ + @Override + public final K acquire() { + K ctx = null; + final Reference ref = ctxTL.get(); + if (ref != null) { + ctx = ref.get(); + } + if (ctx == null) { + // create a new ReentrantContext if none is available + ctx = newContext(); + // update thread local reference: + ctxTL.set(getOrCreateReference(ctx)); + } + // Check reentrance: + if (ctx.usage == USAGE_TL_INACTIVE) { + ctx.usage = USAGE_TL_IN_USE; + } else { + // get or create another ReentrantContext from CLQ provider: + ctx = ctxProviderCLQ.acquire(); + } + return ctx; + } + + /** + * Restore the given ReentrantContext instance for reuse + * + * @param ctx ReentrantContext instance + */ + @Override + public final void release(final K ctx) { + if (ctx.usage == USAGE_TL_IN_USE) { + ctx.usage = USAGE_TL_INACTIVE; + } else { + ctxProviderCLQ.release(ctx); + } + } +} diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java index 226a3d2e30d..6e8da24453e 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -126,7 +126,7 @@ final class ByteArrayCache implements MarlinConst { } if (doChecks) { - check(array, 0, array.length, value); + check(array, fromIndex, toIndex, value); } } @@ -135,9 +135,10 @@ final class ByteArrayCache implements MarlinConst { { if (doChecks) { // check zero on full array: - for (int i = fromIndex; i < toIndex; i++) { + for (int i = 0; i < array.length; i++) { if (array[i] != value) { - logException("Invalid array value at " + i + "\n" + logException("Invalid value at: " + i + " = " + array[i] + + " from: " + fromIndex + " to: " + toIndex + "\n" + Arrays.toString(array), new Throwable()); // ensure array is correctly filled: diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java index 06d7f351e28..681c75d4ceb 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -127,7 +127,7 @@ final class FloatArrayCache implements MarlinConst { } if (doChecks) { - check(array, 0, array.length, value); + check(array, fromIndex, toIndex, value); } } @@ -136,9 +136,10 @@ final class FloatArrayCache implements MarlinConst { { if (doChecks) { // check zero on full array: - for (int i = fromIndex; i < toIndex; i++) { + for (int i = 0; i < array.length; i++) { if (array[i] != value) { - logException("Invalid array value at " + i + "\n" + logException("Invalid value at: " + i + " = " + array[i] + + " from: " + fromIndex + " to: " + toIndex + "\n" + Arrays.toString(array), new Throwable()); // ensure array is correctly filled: diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java index 11c5aae84f6..af4d0b69529 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -126,7 +126,7 @@ final class IntArrayCache implements MarlinConst { } if (doChecks) { - check(array, 0, array.length, value); + check(array, fromIndex, toIndex, value); } } @@ -135,9 +135,10 @@ final class IntArrayCache implements MarlinConst { { if (doChecks) { // check zero on full array: - for (int i = fromIndex; i < toIndex; i++) { + for (int i = 0; i < array.length; i++) { if (array[i] != value) { - logException("Invalid array value at " + i + "\n" + logException("Invalid value at: " + i + " = " + array[i] + + " from: " + fromIndex + " to: " + toIndex + "\n" + Arrays.toString(array), new Throwable()); // ensure array is correctly filled: diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java index 18cb441c571..40afc7fe9a6 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, 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 @@ -590,8 +590,8 @@ public final class MarlinCache implements MarlinConst { alphaRow[to + 1] = 0; } if (doChecks) { - IntArrayCache.check(blkFlags, 0, blkFlags.length, 0); - IntArrayCache.check(alphaRow, 0, alphaRow.length, 0); + IntArrayCache.check(blkFlags, blkW, blkE, 0); + IntArrayCache.check(alphaRow, from, px1 - bboxX0, 0); } if (doMonitors) { diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java index f7b5f7c43a8..e01a5e77f9c 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,11 +30,12 @@ import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Path2D; import java.awt.geom.PathIterator; -import java.lang.ref.Reference; import java.security.AccessController; -import java.util.concurrent.ConcurrentLinkedQueue; import static sun.java2d.marlin.MarlinUtils.logInfo; import sun.awt.geom.PathConsumer2D; +import sun.java2d.ReentrantContextProvider; +import sun.java2d.ReentrantContextProviderCLQ; +import sun.java2d.ReentrantContextProviderTL; import sun.java2d.pipe.AATileGenerator; import sun.java2d.pipe.Region; import sun.java2d.pipe.RenderingEngine; @@ -882,46 +883,50 @@ public class MarlinRenderingEngine extends RenderingEngine // use ThreadLocal or ConcurrentLinkedQueue to get one RendererContext private static final boolean useThreadLocal; - // hard reference - static final int REF_HARD = 0; - // soft reference - static final int REF_SOFT = 1; - // weak reference - static final int REF_WEAK = 2; - // reference type stored in either TL or CLQ static final int REF_TYPE; // Per-thread RendererContext - private static final ThreadLocal rdrCtxThreadLocal; - // RendererContext queue when ThreadLocal is disabled - private static final ConcurrentLinkedQueue rdrCtxQueue; + private static final ReentrantContextProvider rdrCtxProvider; // Static initializer to use TL or CLQ mode static { - // CLQ mode by default: useThreadLocal = MarlinProperties.isUseThreadLocal(); - rdrCtxThreadLocal = (useThreadLocal) ? new ThreadLocal() - : null; - rdrCtxQueue = (!useThreadLocal) ? new ConcurrentLinkedQueue() - : null; // Soft reference by default: - String refType = AccessController.doPrivileged( + final String refType = AccessController.doPrivileged( new GetPropertyAction("sun.java2d.renderer.useRef", "soft")); switch (refType) { default: case "soft": - REF_TYPE = REF_SOFT; + REF_TYPE = ReentrantContextProvider.REF_SOFT; break; case "weak": - REF_TYPE = REF_WEAK; + REF_TYPE = ReentrantContextProvider.REF_WEAK; break; case "hard": - REF_TYPE = REF_HARD; + REF_TYPE = ReentrantContextProvider.REF_HARD; break; } + + if (useThreadLocal) { + rdrCtxProvider = new ReentrantContextProviderTL(REF_TYPE) + { + @Override + protected RendererContext newContext() { + return RendererContext.createContext(); + } + }; + } else { + rdrCtxProvider = new ReentrantContextProviderCLQ(REF_TYPE) + { + @Override + protected RendererContext newContext() { + return RendererContext.createContext(); + } + }; + } } private static boolean settingsLogged = !enableLogs; @@ -936,13 +941,13 @@ public class MarlinRenderingEngine extends RenderingEngine String refType; switch (REF_TYPE) { default: - case REF_HARD: + case ReentrantContextProvider.REF_HARD: refType = "hard"; break; - case REF_SOFT: + case ReentrantContextProvider.REF_SOFT: refType = "soft"; break; - case REF_WEAK: + case ReentrantContextProvider.REF_WEAK: refType = "weak"; break; } @@ -1025,22 +1030,7 @@ public class MarlinRenderingEngine extends RenderingEngine */ @SuppressWarnings({"unchecked"}) static RendererContext getRendererContext() { - RendererContext rdrCtx = null; - final Object ref = (useThreadLocal) ? rdrCtxThreadLocal.get() - : rdrCtxQueue.poll(); - if (ref != null) { - // resolve reference: - rdrCtx = (REF_TYPE == REF_HARD) ? ((RendererContext) ref) - : ((Reference) ref).get(); - } - // create a new RendererContext if none is available - if (rdrCtx == null) { - rdrCtx = RendererContext.createContext(); - if (useThreadLocal) { - // update thread local reference: - rdrCtxThreadLocal.set(rdrCtx.reference); - } - } + final RendererContext rdrCtx = rdrCtxProvider.acquire(); if (doMonitors) { RendererContext.stats.mon_pre_getAATileGenerator.start(); } @@ -1057,8 +1047,6 @@ public class MarlinRenderingEngine extends RenderingEngine if (doMonitors) { RendererContext.stats.mon_pre_getAATileGenerator.stop(); } - if (!useThreadLocal) { - rdrCtxQueue.offer(rdrCtx.reference); - } + rdrCtxProvider.release(rdrCtx); } } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java index f9524c88870..60de2c31570 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,10 @@ package sun.java2d.marlin; import java.awt.geom.Path2D; -import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.concurrent.atomic.AtomicInteger; +import sun.java2d.ReentrantContext; +import sun.java2d.ReentrantContextProvider; import static sun.java2d.marlin.ArrayCache.*; import sun.java2d.marlin.MarlinRenderingEngine.NormalizingPathIterator; import static sun.java2d.marlin.MarlinUtils.logInfo; @@ -36,7 +37,7 @@ import static sun.java2d.marlin.MarlinUtils.logInfo; /** * This class is a renderer context dedicated to a single thread */ -final class RendererContext implements MarlinConst { +final class RendererContext extends ReentrantContext implements MarlinConst { // RendererContext creation counter private static final AtomicInteger contextCount = new AtomicInteger(1); @@ -45,7 +46,7 @@ final class RendererContext implements MarlinConst { ? RendererStats.getInstance(): null; private static final boolean USE_CACHE_HARD_REF = doStats - || (MarlinRenderingEngine.REF_TYPE == MarlinRenderingEngine.REF_WEAK); + || (MarlinRenderingEngine.REF_TYPE == ReentrantContextProvider.REF_WEAK); /** * Create a new renderer context @@ -55,6 +56,7 @@ final class RendererContext implements MarlinConst { static RendererContext createContext() { final RendererContext newCtx = new RendererContext("ctx" + Integer.toString(contextCount.getAndIncrement())); + if (RendererContext.stats != null) { RendererContext.stats.allContexts.add(newCtx); } @@ -63,11 +65,6 @@ final class RendererContext implements MarlinConst { // context name (debugging purposes) final String name; - /* - * Reference to this instance (hard, soft or weak). - * @see MarlinRenderingEngine#REF_TYPE - */ - final Object reference; // Smallest object used as Cleaner's parent reference final Object cleanerObj = new Object(); // dirty flag indicating an exception occured during pipeline in pathTo() @@ -101,7 +98,7 @@ final class RendererContext implements MarlinConst { /** * Constructor * - * @param name + * @param name context name (debugging) */ RendererContext(final String name) { if (logCreateContext) { @@ -124,20 +121,6 @@ final class RendererContext implements MarlinConst { stroker = new Stroker(this); dasher = new Dasher(this); - - // Create the reference to this instance (hard, soft or weak): - switch (MarlinRenderingEngine.REF_TYPE) { - default: - case MarlinRenderingEngine.REF_HARD: - reference = this; - break; - case MarlinRenderingEngine.REF_SOFT: - reference = new SoftReference(this); - break; - case MarlinRenderingEngine.REF_WEAK: - reference = new WeakReference(this); - break; - } } /** diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Version.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Version.java index 94b0e2f1e59..1d144169376 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Version.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Version.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -27,7 +27,7 @@ package sun.java2d.marlin; public final class Version { - private static final String version = "marlin-0.7.3-Unsafe-OpenJDK"; + private static final String version = "marlin-0.7.3.2-Unsafe-OpenJDK"; public static String getVersion() { return version; diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/AAShapePipe.java b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/AAShapePipe.java index e071b967a02..3046ff69c60 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/AAShapePipe.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/AAShapePipe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -28,7 +28,11 @@ import java.awt.BasicStroke; import java.awt.Rectangle; import java.awt.Shape; import java.awt.geom.Rectangle2D; +import java.util.concurrent.ConcurrentLinkedQueue; import sun.awt.SunHints; +import sun.java2d.ReentrantContext; +import sun.java2d.ReentrantContextProvider; +import sun.java2d.ReentrantContextProviderTL; import sun.java2d.SunGraphics2D; /** @@ -38,28 +42,31 @@ import sun.java2d.SunGraphics2D; * This class sets up the Generator and computes the alpha tiles * and then passes them on to a CompositePipe object for painting. */ -public class AAShapePipe +public final class AAShapePipe implements ShapeDrawPipe, ParallelogramPipe { - static RenderingEngine renderengine = RenderingEngine.getInstance(); + static final RenderingEngine renderengine = RenderingEngine.getInstance(); // Per-thread TileState (~1K very small so do not use any Weak Reference) - private static final ThreadLocal tileStateThreadLocal = - new ThreadLocal() { - @Override - protected TileState initialValue() { - return new TileState(); - } - }; + private static final ReentrantContextProvider tileStateProvider = + new ReentrantContextProviderTL( + ReentrantContextProvider.REF_HARD) + { + @Override + protected TileState newContext() { + return new TileState(); + } + }; - CompositePipe outpipe; + final CompositePipe outpipe; public AAShapePipe(CompositePipe pipe) { outpipe = pipe; } + @Override public void draw(SunGraphics2D sg, Shape s) { - BasicStroke bs; + final BasicStroke bs; if (sg.stroke instanceof BasicStroke) { bs = (BasicStroke) sg.stroke; @@ -71,10 +78,12 @@ public class AAShapePipe renderPath(sg, s, bs); } + @Override public void fill(SunGraphics2D sg, Shape s) { renderPath(sg, s, null); } + @Override public void fillParallelogram(SunGraphics2D sg, double ux1, double uy1, double ux2, double uy2, @@ -82,21 +91,23 @@ public class AAShapePipe double dx1, double dy1, double dx2, double dy2) { - Region clip = sg.getCompClip(); - final TileState ts = tileStateThreadLocal.get(); - final int[] abox = ts.abox; + final TileState ts = tileStateProvider.acquire(); + try { + final int[] abox = ts.abox; - AATileGenerator aatg = - renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0, - clip, abox); - if (aatg == null) { - // Nothing to render - return; + final AATileGenerator aatg = + renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0, + sg.getCompClip(), abox); + if (aatg != null) { + renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), + aatg, abox, ts); + } + } finally { + tileStateProvider.release(ts); } - - renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), aatg, abox, ts); } + @Override public void drawParallelogram(SunGraphics2D sg, double ux1, double uy1, double ux2, double uy2, @@ -105,52 +116,61 @@ public class AAShapePipe double dx2, double dy2, double lw1, double lw2) { - Region clip = sg.getCompClip(); - final TileState ts = tileStateThreadLocal.get(); - final int[] abox = ts.abox; + final TileState ts = tileStateProvider.acquire(); + try { + final int[] abox = ts.abox; - AATileGenerator aatg = - renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, lw1, lw2, - clip, abox); - if (aatg == null) { - // Nothing to render - return; + final AATileGenerator aatg = + renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, lw1, + lw2, sg.getCompClip(), abox); + if (aatg != null) { + // Note that bbox is of the original shape, not the wide path. + // This is appropriate for handing to Paint methods... + renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), + aatg, abox, ts); + } + } finally { + tileStateProvider.release(ts); } - - // Note that bbox is of the original shape, not the wide path. - // This is appropriate for handing to Paint methods... - renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), aatg, abox, ts); } public void renderPath(SunGraphics2D sg, Shape s, BasicStroke bs) { - boolean adjust = (bs != null && + final boolean adjust = (bs != null && sg.strokeHint != SunHints.INTVAL_STROKE_PURE); - boolean thin = (sg.strokeState <= SunGraphics2D.STROKE_THINDASHED); + final boolean thin = (sg.strokeState <= SunGraphics2D.STROKE_THINDASHED); - Region clip = sg.getCompClip(); - final TileState ts = tileStateThreadLocal.get(); - final int[] abox = ts.abox; + final TileState ts = tileStateProvider.acquire(); + try { + final int[] abox = ts.abox; - AATileGenerator aatg = - renderengine.getAATileGenerator(s, sg.transform, clip, - bs, thin, adjust, abox); - if (aatg == null) { - // Nothing to render - return; + final AATileGenerator aatg = + renderengine.getAATileGenerator(s, sg.transform, sg.getCompClip(), + bs, thin, adjust, abox); + if (aatg != null) { + renderTiles(sg, s, aatg, abox, ts); + } + } finally { + tileStateProvider.release(ts); } - - renderTiles(sg, s, aatg, abox, ts); } public void renderTiles(SunGraphics2D sg, Shape s, - AATileGenerator aatg, int abox[], TileState ts) + final AATileGenerator aatg, + final int[] abox, final TileState ts) { Object context = null; try { + // reentrance: outpipe may also use AAShapePipe: context = outpipe.startSequence(sg, s, ts.computeDevBox(abox), abox); + // copy of int[] abox as local variables for performance: + final int x0 = abox[0]; + final int y0 = abox[1]; + final int x1 = abox[2]; + final int y1 = abox[3]; + final int tw = aatg.getTileWidth(); final int th = aatg.getTileHeight(); @@ -158,16 +178,15 @@ public class AAShapePipe final byte[] alpha = ts.getAlphaTile(tw * th); byte[] atile; - for (int y = abox[1]; y < abox[3]; y += th) { - int h = Math.min(th, abox[3] - y); + for (int y = y0; y < y1; y += th) { + final int h = Math.min(th, y1 - y); - for (int x = abox[0]; x < abox[2]; x += tw) { - int w = Math.min(tw, abox[2] - x); + for (int x = x0; x < x1; x += tw) { + final int w = Math.min(tw, x1 - x); - int a = aatg.getTypicalAlpha(); - if (a == 0x00 || - outpipe.needTile(context, x, y, w, h) == false) - { + final int a = aatg.getTypicalAlpha(); + + if (a == 0x00 || !outpipe.needTile(context, x, y, w, h)) { aatg.nextTile(); outpipe.skipTile(context, x, y); continue; @@ -180,8 +199,7 @@ public class AAShapePipe aatg.getAlpha(alpha, 0, tw); } - outpipe.renderPathTile(context, atile, 0, tw, - x, y, w, h); + outpipe.renderPathTile(context, atile, 0, tw, x, y, w, h); } } } finally { @@ -193,7 +211,7 @@ public class AAShapePipe } // Tile state used by AAShapePipe - static final class TileState { + static final class TileState extends ReentrantContext { // cached tile (32 x 32 tile by default) private byte[] theTile = new byte[32 * 32]; // dirty aabox array @@ -240,5 +258,4 @@ public class AAShapePipe return box; } } - } diff --git a/jdk/test/sun/java2d/marlin/CrashPaintTest.java b/jdk/test/sun/java2d/marlin/CrashPaintTest.java new file mode 100644 index 00000000000..cf710bc83a5 --- /dev/null +++ b/jdk/test/sun/java2d/marlin/CrashPaintTest.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2016, 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.awt.Color; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.PaintContext; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.TexturePaint; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.io.File; +import java.io.IOException; +import java.util.Locale; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import javax.imageio.ImageIO; + +/** + * @test + * @bug 8148886 + * @summary Verifies that Marlin supports reentrant operations (ThreadLocal) + * like in custom Paint or custom Composite + * @run main CrashPaintTest + */ +public class CrashPaintTest { + + static final boolean SAVE_IMAGE = false; + + public static void main(String argv[]) { + Locale.setDefault(Locale.US); + + // initialize j.u.l Looger: + final Logger log = Logger.getLogger("sun.java2d.marlin"); + log.addHandler(new Handler() { + @Override + public void publish(LogRecord record) { + Throwable th = record.getThrown(); + // detect any Throwable: + if (th != null) { + System.out.println("Test failed:\n" + record.getMessage()); + th.printStackTrace(System.out); + + throw new RuntimeException("Test failed: ", th); + } + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + }); + + // enable Marlin logging & internal checks: + System.setProperty("sun.java2d.renderer.log", "true"); + System.setProperty("sun.java2d.renderer.useLogger", "true"); + System.setProperty("sun.java2d.renderer.doChecks", "true"); + + // Force using thread-local storage: + System.setProperty("sun.java2d.renderer.useThreadLocal", "true"); + // Force smaller pixelsize to force using array caches: + System.setProperty("sun.java2d.renderer.pixelsize", "256"); + + final int width = 300; + final int height = 300; + + final BufferedImage image = new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB); + + final Graphics2D g2d = (Graphics2D) image.getGraphics(); + try { + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + g2d.setBackground(Color.WHITE); + g2d.clearRect(0, 0, width, height); + + final Ellipse2D.Double ellipse + = new Ellipse2D.Double(0, 0, width, height); + + final Paint paint = new CustomPaint(100); + + for (int i = 0; i < 20; i++) { + final long start = System.nanoTime(); + g2d.setPaint(paint); + g2d.fill(ellipse); + + g2d.setColor(Color.GREEN); + g2d.draw(ellipse); + + final long time = System.nanoTime() - start; + System.out.println("paint: duration= " + (1e-6 * time) + " ms."); + } + + if (SAVE_IMAGE) { + try { + final File file = new File("CrashPaintTest.png"); + System.out.println("Writing file: " + + file.getAbsolutePath()); + ImageIO.write(image, "PNG", file); + } catch (IOException ex) { + System.out.println("Writing file failure:"); + ex.printStackTrace(); + } + } + + // Check image on few pixels: + final Raster raster = image.getData(); + + // 170, 175 = blue + checkPixel(raster, 170, 175, Color.BLUE.getRGB()); + // 50, 50 = blue + checkPixel(raster, 50, 50, Color.BLUE.getRGB()); + + // 190, 110 = pink + checkPixel(raster, 190, 110, Color.PINK.getRGB()); + // 280, 210 = pink + checkPixel(raster, 280, 210, Color.PINK.getRGB()); + + } finally { + g2d.dispose(); + } + } + + private static void checkPixel(final Raster raster, + final int x, final int y, + final int expected) { + + final int[] rgb = (int[]) raster.getDataElements(x, y, null); + + if (rgb[0] != expected) { + throw new IllegalStateException("bad pixel at (" + x + ", " + y + + ") = " + rgb[0] + " expected: " + expected); + } + } + + private static class CustomPaint extends TexturePaint { + private int size; + + CustomPaint(final int size) { + super(new BufferedImage(size, size, + BufferedImage.TYPE_INT_ARGB), + new Rectangle2D.Double(0, 0, size, size) + ); + this.size = size; + } + + @Override + public PaintContext createContext(ColorModel cm, + Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform at, + RenderingHints hints) { + + // Fill bufferedImage using + final Graphics2D g2d = (Graphics2D) getImage().getGraphics(); + try { + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setBackground(Color.PINK); + g2d.clearRect(0, 0, size, size); + + g2d.setColor(Color.BLUE); + g2d.drawRect(0, 0, size, size); + + g2d.fillOval(size / 10, size / 10, + size * 8 / 10, size * 8 / 10); + + } finally { + g2d.dispose(); + } + + return super.createContext(cm, deviceBounds, userBounds, at, hints); + } + } +} From 44c03b15e225c4817560ed09e497cc7c3166b49f Mon Sep 17 00:00:00 2001 From: Timo Kinnunen Date: Tue, 23 Feb 2016 18:58:36 -0500 Subject: [PATCH 055/183] 8150426: Wrong cast in metadata_at_put Fix cast. Reviewed-by: dholmes, coleenp, jprovino --- hotspot/src/share/vm/oops/typeArrayOop.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/oops/typeArrayOop.hpp b/hotspot/src/share/vm/oops/typeArrayOop.hpp index e4670a8949b..8ab2f4d1f74 100644 --- a/hotspot/src/share/vm/oops/typeArrayOop.hpp +++ b/hotspot/src/share/vm/oops/typeArrayOop.hpp @@ -129,7 +129,7 @@ class typeArrayOopDesc : public arrayOopDesc { Metadata* metadata_at(int which) const { return (Metadata*)*long_at_addr(which); } void metadata_at_put(int which, Metadata* contents) { - *long_at_addr(which) = (long)contents; + *long_at_addr(which) = (jlong)contents; } #else Metadata* metadata_at(int which) const { From 3634fb9df2a8f1b117ecce947f14a3079e1cd783 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 24 Feb 2016 18:06:34 +0100 Subject: [PATCH 056/183] 8149036: Add tracing for thread related events at os level Reviewed-by: coleenp, mlarsson, dholmes --- hotspot/src/os/aix/vm/os_aix.cpp | 49 ++++++++++-------------- hotspot/src/os/bsd/vm/os_bsd.cpp | 22 +++++++++-- hotspot/src/os/linux/vm/os_linux.cpp | 21 ++++++++-- hotspot/src/os/posix/vm/os_posix.cpp | 13 +++++++ hotspot/src/os/posix/vm/os_posix.hpp | 5 +++ hotspot/src/os/solaris/vm/os_solaris.cpp | 42 ++++++++++++++++++-- hotspot/src/os/windows/vm/os_windows.cpp | 44 ++++++++++++++++++++- hotspot/src/share/vm/logging/logTag.hpp | 1 + hotspot/src/share/vm/runtime/thread.cpp | 34 +++++++++++++--- 9 files changed, 187 insertions(+), 44 deletions(-) diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index f63a789b89c..c38d2a3fbd0 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -36,6 +36,7 @@ #include "compiler/compileBroker.hpp" #include "interpreter/interpreter.hpp" #include "jvm_aix.h" +#include "logging/log.hpp" #include "libo4.hpp" #include "libperfstat_aix.hpp" #include "libodm_aix.hpp" @@ -791,13 +792,8 @@ static void *java_start(Thread *thread) { const pthread_t pthread_id = ::pthread_self(); const tid_t kernel_thread_id = ::thread_self(); - trcVerbose("newborn Thread : pthread-id %u, ktid " UINT64_FORMAT - ", stack %p ... %p, stacksize 0x%IX (%IB)", - pthread_id, kernel_thread_id, - thread->stack_end(), - thread->stack_base(), - thread->stack_size(), - thread->stack_size()); + log_info(os, thread)("Thread is alive (pthread id " UINTX_FORMAT ", tid " UINTX_FORMAT ")", + (uintx) pthread_id, (uintx) kernel_thread_id); // Normally, pthread stacks on AIX live in the data segment (are allocated with malloc() // by the pthread library). In rare cases, this may not be the case, e.g. when third-party @@ -805,7 +801,7 @@ static void *java_start(Thread *thread) { // guard pages on those stacks, because the stacks may reside in memory which is not // protectable (shmated). if (thread->stack_base() > ::sbrk(0)) { - trcVerbose("Thread " UINT64_FORMAT ": stack not in data segment.", (uint64_t) pthread_id); + log_warning(os, thread)("Thread " UINTX_FORMAT ": stack not in data segment.", (uintx)pthread_id); } // Try to randomize the cache line index of hot stack frames. @@ -839,8 +835,8 @@ static void *java_start(Thread *thread) { // Call one more level start routine. thread->run(); - trcVerbose("Thread finished : pthread-id %u, ktid " UINT64_FORMAT ".", - pthread_id, kernel_thread_id); + log_info(os, thread)("Thread finished (pthread id " UINTX_FORMAT ", tid " UINTX_FORMAT ").", + (uintx) pthread_id, (uintx) kernel_thread_id); return 0; } @@ -908,20 +904,19 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { pthread_t tid; int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread); + + char buf[64]; + if (ret == 0) { + log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } else { + log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", + strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } + pthread_attr_destroy(&attr); - if (ret == 0) { - trcVerbose("Created New Thread : pthread-id %u", tid); - } else { - if (os::Aix::on_pase()) { - // QIBM_MULTI_THREADED=Y is needed when the launcher is started on iSeries - // using QSH. Otherwise pthread_create fails with errno=11. - trcVerbose("(Please make sure you set the environment variable " - "QIBM_MULTI_THREADED=Y before running this program.)"); - } - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("pthread_create()"); - } + if (ret != 0) { // Need to clean up stuff we've allocated so far thread->set_osthread(NULL); delete osthread; @@ -958,13 +953,6 @@ bool os::create_attached_thread(JavaThread* thread) { const pthread_t pthread_id = ::pthread_self(); const tid_t kernel_thread_id = ::thread_self(); - trcVerbose("attaching Thread : pthread-id %u, ktid " UINT64_FORMAT ", stack %p ... %p, stacksize 0x%IX (%IB)", - pthread_id, kernel_thread_id, - thread->stack_end(), - thread->stack_base(), - thread->stack_size(), - thread->stack_size()); - // OSThread::thread_id is the pthread id. osthread->set_thread_id(pthread_id); @@ -990,6 +978,9 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Aix::hotspot_sigmask(thread); + log_info(os, thread)("Thread attached (pthread id " UINTX_FORMAT ", tid " UINTX_FORMAT ")", + (uintx) pthread_id, (uintx) kernel_thread_id); + return true; } diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 8fdc6bc63b7..51fce416eda 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -32,6 +32,7 @@ #include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "jvm_bsd.h" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "mutex_bsd.inline.hpp" @@ -681,6 +682,9 @@ static void *java_start(Thread *thread) { osthread->set_thread_id(os::Bsd::gettid()); + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ".", + os::current_thread_id(), (uintx) pthread_self()); + #ifdef __APPLE__ uint64_t unique_thread_id = locate_unique_thread_id(osthread->thread_id()); guarantee(unique_thread_id != 0, "unique thread id was not found"); @@ -716,6 +720,9 @@ static void *java_start(Thread *thread) { // call one more level start routine thread->run(); + log_info(os, thread)("Thread finished (tid " UINTX_FORMAT ", pthread id " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + return 0; } @@ -776,12 +783,18 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { pthread_t tid; int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread); + char buf[64]; + if (ret == 0) { + log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } else { + log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", + strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } + pthread_attr_destroy(&attr); if (ret != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("pthread_create()"); - } // Need to clean up stuff we've allocated so far thread->set_osthread(NULL); delete osthread; @@ -858,6 +871,9 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Bsd::hotspot_sigmask(thread); + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ".", + os::current_thread_id(), (uintx) pthread_self()); + return true; } diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 3783351c345..5bf366d3997 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -662,6 +662,9 @@ static void *java_start(Thread *thread) { osthread->set_thread_id(os::current_thread_id()); + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + if (UseNUMA) { int lgrp_id = os::numa_get_group_id(); if (lgrp_id != -1) { @@ -691,6 +694,9 @@ static void *java_start(Thread *thread) { // call one more level start routine thread->run(); + log_info(os, thread)("Thread finished (tid " UINTX_FORMAT ", pthread id " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + return 0; } @@ -756,12 +762,18 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, pthread_t tid; int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread); + char buf[64]; + if (ret == 0) { + log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } else { + log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", + strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } + pthread_attr_destroy(&attr); if (ret != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("pthread_create()"); - } // Need to clean up stuff we've allocated so far thread->set_osthread(NULL); delete osthread; @@ -858,6 +870,9 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Linux::hotspot_sigmask(thread); + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + return true; } diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp index 8cccda34d21..85407bd3cad 100644 --- a/hotspot/src/os/posix/vm/os_posix.cpp +++ b/hotspot/src/os/posix/vm/os_posix.cpp @@ -1071,6 +1071,19 @@ void os::Posix::ucontext_set_pc(ucontext_t* ctx, address pc) { #endif } +char* os::Posix::describe_pthread_attr(char* buf, size_t buflen, const pthread_attr_t* attr) { + size_t stack_size = 0; + size_t guard_size = 0; + int detachstate = 0; + pthread_attr_getstacksize(attr, &stack_size); + pthread_attr_getguardsize(attr, &guard_size); + pthread_attr_getdetachstate(attr, &detachstate); + jio_snprintf(buf, buflen, "stacksize: " SIZE_FORMAT "k, guardsize: " SIZE_FORMAT "k, %s", + stack_size / 1024, guard_size / 1024, + (detachstate == PTHREAD_CREATE_DETACHED ? "detached" : "joinable")); + return buf; +} + os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() { assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread"); diff --git a/hotspot/src/os/posix/vm/os_posix.hpp b/hotspot/src/os/posix/vm/os_posix.hpp index be464ea8fa1..0196e989456 100644 --- a/hotspot/src/os/posix/vm/os_posix.hpp +++ b/hotspot/src/os/posix/vm/os_posix.hpp @@ -76,6 +76,11 @@ public: static address ucontext_get_pc(const ucontext_t* ctx); // Set PC into context. Needed for continuation after signal. static void ucontext_set_pc(ucontext_t* ctx, address pc); + + // Helper function; describes pthread attributes as short string. String is written + // to buf with len buflen; buf is returned. + static char* describe_pthread_attr(char* buf, size_t buflen, const pthread_attr_t* attr); + }; /* diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index ae008b6dbe9..e454ed165c7 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -32,6 +32,7 @@ #include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "jvm_solaris.h" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "mutex_solaris.inline.hpp" @@ -68,6 +69,7 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" #include "utilities/vmError.hpp" // put OS-includes here @@ -736,6 +738,9 @@ extern "C" void* java_start(void* thread_addr) { osthr->set_lwp_id(_lwp_self()); // Store lwp in case we are bound thread->_schedctl = (void *) schedctl_init(); + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").", + os::current_thread_id()); + if (UseNUMA) { int lgrp_id = os::numa_get_group_id(); if (lgrp_id != -1) { @@ -781,6 +786,8 @@ extern "C" void* java_start(void* thread_addr) { Atomic::dec(&os::Solaris::_os_thread_count); } + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ").", os::current_thread_id()); + if (UseDetachedThreads) { thr_exit(NULL); ShouldNotReachHere(); @@ -853,6 +860,9 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Solaris::hotspot_sigmask(thread); + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ").", + os::current_thread_id()); + return true; } @@ -879,6 +889,25 @@ bool os::create_main_thread(JavaThread* thread) { return true; } +// Helper function to trace thread attributes, similar to os::Posix::describe_pthread_attr() +static char* describe_thr_create_attributes(char* buf, size_t buflen, + size_t stacksize, long flags) +{ + stringStream ss(buf, buflen); + ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024); + ss.print("flags: "); + #define PRINT_FLAG(f) if (flags & f) ss.print( XSTR(f) " "); + #define ALL(X) \ + X(THR_SUSPENDED) \ + X(THR_DETACHED) \ + X(THR_BOUND) \ + X(THR_NEW_LWP) \ + X(THR_DAEMON) + ALL(PRINT_FLAG) + #undef ALL + #undef PRINT_FLAG + return buf; +} bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { @@ -974,10 +1003,17 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, osthread->set_thread_id(-1); status = thr_create(NULL, stack_size, java_start, thread, flags, &tid); + + char buf[64]; + if (status == 0) { + log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + (uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); + } else { + log_warning(os, thread)("Failed to start thread - thr_create failed (%s) for attributes: %s.", + strerror(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); + } + if (status != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("os::create_thread"); - } thread->set_osthread(NULL); // Need to clean up stuff we've allocated so far delete osthread; diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 19d7319e7e1..cc15183b186 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -35,6 +35,7 @@ #include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "jvm_windows.h" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "mutex_windows.inline.hpp" @@ -71,6 +72,7 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" #include "utilities/vmError.hpp" #ifdef _DEBUG @@ -436,6 +438,8 @@ static unsigned __stdcall java_start(Thread* thread) { res = 20115; // java thread } + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").", os::current_thread_id()); + // Install a win32 structured exception handler around every thread created // by VM, so VM can generate error dump when an exception occurred in non- // Java thread (e.g. VM thread). @@ -446,6 +450,8 @@ static unsigned __stdcall java_start(Thread* thread) { // Nothing to do. } + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ").", os::current_thread_id()); + // One less thread is executing // When the VMThread gets here, the main thread may have already exited // which frees the CodeHeap containing the Atomic::add code @@ -509,6 +515,10 @@ bool os::create_attached_thread(JavaThread* thread) { osthread->set_state(RUNNABLE); thread->set_osthread(osthread); + + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ").", + os::current_thread_id()); + return true; } @@ -530,6 +540,28 @@ bool os::create_main_thread(JavaThread* thread) { return true; } +// Helper function to trace _beginthreadex attributes, +// similar to os::Posix::describe_pthread_attr() +static char* describe_beginthreadex_attributes(char* buf, size_t buflen, + size_t stacksize, unsigned initflag) +{ + stringStream ss(buf, buflen); + if (stacksize == 0) { + ss.print("stacksize: default, "); + } else { + ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024); + } + ss.print("flags: "); + #define PRINT_FLAG(f) if (initflag & f) ss.print( XSTR(f) " "); + #define ALL(X) \ + X(CREATE_SUSPENDED) \ + X(STACK_SIZE_PARAM_IS_A_RESERVATION) + ALL(PRINT_FLAG) + #undef ALL + #undef PRINT_FLAG + return buf; +} + // Allocate and initialize a new OSThread bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { @@ -596,14 +628,24 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, // document because JVM uses C runtime library. The good news is that the // flag appears to work with _beginthredex() as well. + const unsigned initflag = CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION; HANDLE thread_handle = (HANDLE)_beginthreadex(NULL, (unsigned)stack_size, (unsigned (__stdcall *)(void*)) java_start, thread, - CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, + initflag, &thread_id); + char buf[64]; + if (thread_handle != NULL) { + log_info(os, thread)("Thread started (tid: %u, attributes: %s)", + thread_id, describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); + } else { + log_warning(os, thread)("Failed to start thread - _beginthreadex failed (%s) for attributes: %s.", + strerror(errno), describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); + } + if (thread_handle == NULL) { // Need to clean up stuff we've allocated so far CloseHandle(osthread->interrupt_event()); diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp index 60e39f710f5..16a91cfbddf 100644 --- a/hotspot/src/share/vm/logging/logTag.hpp +++ b/hotspot/src/share/vm/logging/logTag.hpp @@ -81,6 +81,7 @@ LOG_TAG(survivor) \ LOG_TAG(sweep) \ LOG_TAG(task) \ + LOG_TAG(thread) \ LOG_TAG(tlab) \ LOG_TAG(time) \ LOG_TAG(verify) \ diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 267c6584c37..654aebd9e70 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -324,6 +324,10 @@ void Thread::record_stack_base_and_size() { // record thread's native stack, stack grows downward MemTracker::record_thread_stack(stack_end(), stack_size()); #endif // INCLUDE_NMT + log_debug(os, thread)("Thread " UINTX_FORMAT " stack dimensions: " + PTR_FORMAT "-" PTR_FORMAT " (" SIZE_FORMAT "k).", + os::current_thread_id(), p2i(stack_base() - stack_size()), + p2i(stack_base()), stack_size()/1024); } @@ -1802,6 +1806,10 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { // Call after last event on thread EVENT_THREAD_EXIT(this); + log_info(os, thread)("Thread " UINTX_FORMAT " %s.", + os::current_thread_id(), + exit_type == JavaThread::normal_exit ? "exiting" : "detaching"); + // Call Thread.exit(). We try 3 times in case we got another Thread.stop during // the execution of the method. If that is not enough, then we don't really care. Thread.stop // is deprecated anyhow. @@ -2491,18 +2499,25 @@ void JavaThread::create_stack_guard_pages() { // warning("Guarding at " PTR_FORMAT " for len " SIZE_FORMAT "\n", low_addr, len); if (allocate && !os::create_stack_guard_pages((char *) low_addr, len)) { - warning("Attempt to allocate stack guard pages failed."); + log_warning(os, thread)("Attempt to allocate stack guard pages failed."); return; } if (os::guard_memory((char *) low_addr, len)) { _stack_guard_state = stack_guard_enabled; } else { - warning("Attempt to protect stack guard pages failed."); + log_warning(os, thread)("Attempt to protect stack guard pages failed (" + PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len)); if (os::uncommit_memory((char *) low_addr, len)) { - warning("Attempt to deallocate stack guard pages failed."); + log_warning(os, thread)("Attempt to deallocate stack guard pages failed."); } + return; } + + log_debug(os, thread)("Thread " UINTX_FORMAT " stack guard pages activated: " + PTR_FORMAT "-" PTR_FORMAT ".", + os::current_thread_id(), p2i(low_addr), p2i(low_addr + len)); + } void JavaThread::remove_stack_guard_pages() { @@ -2515,16 +2530,25 @@ void JavaThread::remove_stack_guard_pages() { if (os::remove_stack_guard_pages((char *) low_addr, len)) { _stack_guard_state = stack_guard_unused; } else { - warning("Attempt to deallocate stack guard pages failed."); + log_warning(os, thread)("Attempt to deallocate stack guard pages failed (" + PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len)); + return; } } else { if (_stack_guard_state == stack_guard_unused) return; if (os::unguard_memory((char *) low_addr, len)) { _stack_guard_state = stack_guard_unused; } else { - warning("Attempt to unprotect stack guard pages failed."); + log_warning(os, thread)("Attempt to unprotect stack guard pages failed (" + PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len)); + return; } } + + log_debug(os, thread)("Thread " UINTX_FORMAT " stack guard pages removed: " + PTR_FORMAT "-" PTR_FORMAT ".", + os::current_thread_id(), p2i(low_addr), p2i(low_addr + len)); + } void JavaThread::enable_stack_reserved_zone() { From 5d5113046a2273da15da3eb65e5dd6a7e5478393 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 24 Feb 2016 13:18:54 -0500 Subject: [PATCH 057/183] 8150419: Cleanup BufferNode API Fewer public functions, cleanup allocation. Reviewed-by: tschatzl, drwhite --- hotspot/src/share/vm/gc/g1/ptrQueue.cpp | 60 +++++++++++++++++-------- hotspot/src/share/vm/gc/g1/ptrQueue.hpp | 55 ++++++++++------------- 2 files changed, 65 insertions(+), 50 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp index 756b9599fb8..55b41a0b605 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,8 @@ #include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" +#include + PtrQueue::PtrQueue(PtrQueueSet* qset, bool permanent, bool active) : _qset(qset), _buf(NULL), _index(0), _sz(0), _active(active), _permanent(permanent), _lock(NULL) @@ -87,6 +89,19 @@ void PtrQueue::locking_enqueue_completed_buffer(void** buf) { } +BufferNode* BufferNode::allocate(size_t byte_size) { + assert(byte_size > 0, "precondition"); + assert(is_size_aligned(byte_size, sizeof(void**)), + "Invalid buffer size " SIZE_FORMAT, byte_size); + void* data = NEW_C_HEAP_ARRAY(char, buffer_offset() + byte_size, mtGC); + return new (data) BufferNode; +} + +void BufferNode::deallocate(BufferNode* node) { + node->~BufferNode(); + FREE_C_HEAP_ARRAY(char, node); +} + PtrQueueSet::PtrQueueSet(bool notify_when_complete) : _max_completed_queue(0), _cbl_mon(NULL), _fl_lock(NULL), @@ -123,17 +138,23 @@ void PtrQueueSet::initialize(Monitor* cbl_mon, void** PtrQueueSet::allocate_buffer() { assert(_sz > 0, "Didn't set a buffer size."); - MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag); - if (_fl_owner->_buf_free_list != NULL) { - void** res = BufferNode::make_buffer_from_node(_fl_owner->_buf_free_list); - _fl_owner->_buf_free_list = _fl_owner->_buf_free_list->next(); - _fl_owner->_buf_free_list_sz--; - return res; - } else { - // Allocate space for the BufferNode in front of the buffer. - char *b = NEW_C_HEAP_ARRAY(char, _sz + BufferNode::aligned_size(), mtGC); - return BufferNode::make_buffer_from_block(b); + BufferNode* node = NULL; + { + MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag); + node = _fl_owner->_buf_free_list; + if (node != NULL) { + _fl_owner->_buf_free_list = node->next(); + _fl_owner->_buf_free_list_sz--; + } } + if (node == NULL) { + node = BufferNode::allocate(_sz); + } else { + // Reinitialize buffer obtained from free list. + node->set_index(0); + node->set_next(NULL); + } + return BufferNode::make_buffer_from_node(node); } void PtrQueueSet::deallocate_buffer(void** buf) { @@ -150,13 +171,13 @@ void PtrQueueSet::reduce_free_list() { // For now we'll adopt the strategy of deleting half. MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag); size_t n = _buf_free_list_sz / 2; - while (n > 0) { - assert(_buf_free_list != NULL, "_buf_free_list_sz must be wrong."); - void* b = BufferNode::make_block_from_node(_buf_free_list); - _buf_free_list = _buf_free_list->next(); - FREE_C_HEAP_ARRAY(char, b); - _buf_free_list_sz --; - n--; + for (size_t i = 0; i < n; ++i) { + assert(_buf_free_list != NULL, + "_buf_free_list_sz is wrong: " SIZE_FORMAT, _buf_free_list_sz); + BufferNode* node = _buf_free_list; + _buf_free_list = node->next(); + _buf_free_list_sz--; + BufferNode::deallocate(node); } } @@ -236,8 +257,9 @@ bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) { void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) { MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); - BufferNode* cbn = BufferNode::new_from_buffer(buf); + BufferNode* cbn = BufferNode::make_node_from_buffer(buf); cbn->set_index(index); + cbn->set_next(NULL); if (_completed_buffers_tail == NULL) { assert(_completed_buffers_head == NULL, "Well-formedness"); _completed_buffers_head = cbn; diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp index 707d591c0c0..a2207641238 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,9 +33,6 @@ // the addresses of modified old-generation objects. This type supports // this operation. -// The definition of placement operator new(size_t, void*) in the . -#include - class PtrQueueSet; class PtrQueue VALUE_OBJ_CLASS_SPEC { friend class VMStructs; @@ -168,42 +165,38 @@ protected: class BufferNode { size_t _index; BufferNode* _next; -public: + void* _buffer[1]; // Pseudo flexible array member. + BufferNode() : _index(0), _next(NULL) { } + ~BufferNode() { } + + static size_t buffer_offset() { + return offset_of(BufferNode, _buffer); + } + +public: BufferNode* next() const { return _next; } void set_next(BufferNode* n) { _next = n; } size_t index() const { return _index; } void set_index(size_t i) { _index = i; } - // Align the size of the structure to the size of the pointer - static size_t aligned_size() { - static const size_t alignment = round_to(sizeof(BufferNode), sizeof(void*)); - return alignment; + // Allocate a new BufferNode with the "buffer" having size bytes. + static BufferNode* allocate(size_t byte_size); + + // Free a BufferNode. + static void deallocate(BufferNode* node); + + // Return the BufferNode containing the buffer. + static BufferNode* make_node_from_buffer(void** buffer) { + return reinterpret_cast( + reinterpret_cast(buffer) - buffer_offset()); } - // BufferNode is allocated before the buffer. - // The chunk of memory that holds both of them is a block. - - // Produce a new BufferNode given a buffer. - static BufferNode* new_from_buffer(void** buf) { - return new (make_block_from_buffer(buf)) BufferNode; - } - - // The following are the required conversion routines: - static BufferNode* make_node_from_buffer(void** buf) { - return (BufferNode*)make_block_from_buffer(buf); - } + // Return the buffer for node. static void** make_buffer_from_node(BufferNode *node) { - return make_buffer_from_block(node); - } - static void* make_block_from_node(BufferNode *node) { - return (void*)node; - } - static void** make_buffer_from_block(void* p) { - return (void**)((char*)p + aligned_size()); - } - static void* make_block_from_buffer(void** p) { - return (void*)((char*)p - aligned_size()); + // &_buffer[0] might lead to index out of bounds warnings. + return reinterpret_cast( + reinterpret_cast(node) + buffer_offset()); } }; From 453c5ef3758028d9c4cf4707e2487e5266352e69 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 24 Feb 2016 16:04:51 -0500 Subject: [PATCH 058/183] 8150506: Remove unused locks Reviewed-by: mgronlun, tschatzl, mgerdin, coleenp --- hotspot/src/share/vm/runtime/fprofiler.cpp | 5 ++--- hotspot/src/share/vm/runtime/mutex.cpp | 5 +---- hotspot/src/share/vm/runtime/mutexLocker.cpp | 14 +------------- hotspot/src/share/vm/runtime/mutexLocker.hpp | 7 +------ 4 files changed, 5 insertions(+), 26 deletions(-) diff --git a/hotspot/src/share/vm/runtime/fprofiler.cpp b/hotspot/src/share/vm/runtime/fprofiler.cpp index fbc51b4047d..fc687618e03 100644 --- a/hotspot/src/share/vm/runtime/fprofiler.cpp +++ b/hotspot/src/share/vm/runtime/fprofiler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -836,8 +836,7 @@ void FlatProfiler::record_vm_tick() { vm_thread_profiler->inc_thread_ticks(); // Get a snapshot of a current VMThread pc (and leave it running!) - // The call may fail if, for instance the VM thread is interrupted while - // holding the Interrupt_lock or for other reasons. + // The call may fail in some circumstances epc = os::get_thread_pc(VMThread::vm_thread()); if(epc.pc() != NULL) { if (os::dll_address_to_function_name(epc.pc(), buf, sizeof(buf), NULL)) { diff --git a/hotspot/src/share/vm/runtime/mutex.cpp b/hotspot/src/share/vm/runtime/mutex.cpp index 81fa378d05c..ef6ac43b5d6 100644 --- a/hotspot/src/share/vm/runtime/mutex.cpp +++ b/hotspot/src/share/vm/runtime/mutex.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, 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 @@ -1320,15 +1320,12 @@ void Monitor::set_owner_implementation(Thread *new_owner) { // The rank Mutex::native is an exception in that it is not subject // to the verification rules. // Here are some further notes relating to mutex acquisition anomalies: - // . under Solaris, the interrupt lock gets acquired when doing - // profiling, so any lock could be held. // . it is also ok to acquire Safepoint_lock at the very end while we // already hold Terminator_lock - may happen because of periodic safepoints if (this->rank() != Mutex::native && this->rank() != Mutex::suspend_resume && locks != NULL && locks->rank() <= this->rank() && !SafepointSynchronize::is_at_safepoint() && - this != Interrupt_lock && this != ProfileVM_lock && !(this == Safepoint_lock && contains(locks, Terminator_lock) && SafepointSynchronize::is_synchronizing())) { new_owner->print_owned_locks(); diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index ae1d213b6e5..fa1aea26a55 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -50,7 +50,6 @@ Mutex* JmethodIdCreation_lock = NULL; Mutex* JfieldIdCreation_lock = NULL; Monitor* JNICritical_lock = NULL; Mutex* JvmtiThreadState_lock = NULL; -Monitor* JvmtiPendingEvent_lock = NULL; Monitor* Heap_lock = NULL; Mutex* ExpandHeap_lock = NULL; Mutex* AdapterHandlerLibrary_lock = NULL; @@ -73,8 +72,6 @@ Monitor* CGC_lock = NULL; Monitor* STS_lock = NULL; Monitor* SLT_lock = NULL; Monitor* FullGCCount_lock = NULL; -Monitor* CMark_lock = NULL; -Mutex* CMRegionStack_lock = NULL; Mutex* SATB_Q_FL_lock = NULL; Monitor* SATB_Q_CBL_mon = NULL; Mutex* Shared_SATB_Q_lock = NULL; @@ -94,11 +91,8 @@ Mutex* MultiArray_lock = NULL; Monitor* Terminator_lock = NULL; Monitor* BeforeExit_lock = NULL; Monitor* Notify_lock = NULL; -Monitor* Interrupt_lock = NULL; -Monitor* ProfileVM_lock = NULL; Mutex* ProfilePrint_lock = NULL; Mutex* ExceptionCache_lock = NULL; -Monitor* ObjAllocPost_lock = NULL; Mutex* OsrList_lock = NULL; #ifndef PRODUCT @@ -184,8 +178,6 @@ void mutex_init() { } if (UseG1GC) { - def(CMark_lock , Monitor, nonleaf, true, Monitor::_safepoint_check_never); // coordinate concurrent mark thread - def(CMRegionStack_lock , Mutex, leaf, true, Monitor::_safepoint_check_never); def(SATB_Q_FL_lock , Mutex , special, true, Monitor::_safepoint_check_never); def(SATB_Q_CBL_mon , Monitor, nonleaf, true, Monitor::_safepoint_check_never); def(Shared_SATB_Q_lock , Mutex, nonleaf, true, Monitor::_safepoint_check_never); @@ -206,12 +198,10 @@ void mutex_init() { def(ParGCRareEvent_lock , Mutex , leaf , true, Monitor::_safepoint_check_sometimes); def(DerivedPointerTableGC_lock , Mutex, leaf, true, Monitor::_safepoint_check_never); def(CodeCache_lock , Mutex , special, true, Monitor::_safepoint_check_never); - def(Interrupt_lock , Monitor, special, true, Monitor::_safepoint_check_never); // used for interrupt processing def(RawMonitor_lock , Mutex, special, true, Monitor::_safepoint_check_never); def(OopMapCacheAlloc_lock , Mutex, leaf, true, Monitor::_safepoint_check_always); // used for oop_map_cache allocation. def(Patching_lock , Mutex , special, true, Monitor::_safepoint_check_never); // used for safepointing and code patching. - def(ObjAllocPost_lock , Monitor, special, false, Monitor::_safepoint_check_never); def(Service_lock , Monitor, special, true, Monitor::_safepoint_check_never); // used for service thread operations def(JmethodIdCreation_lock , Mutex , leaf, true, Monitor::_safepoint_check_always); // used for creating jmethodIDs. @@ -267,7 +257,6 @@ void mutex_init() { def(MultiArray_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // locks SymbolTable_lock def(JvmtiThreadState_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // Used by JvmtiThreadState/JvmtiEventController - def(JvmtiPendingEvent_lock , Monitor, nonleaf, false, Monitor::_safepoint_check_never); // Used by JvmtiCodeBlobEvents def(Management_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // used for JVM management def(Compile_lock , Mutex , nonleaf+3, true, Monitor::_safepoint_check_sometimes); @@ -277,7 +266,6 @@ void mutex_init() { def(MethodCompileQueue_lock , Monitor, nonleaf+4, true, Monitor::_safepoint_check_always); def(Debug2_lock , Mutex , nonleaf+4, true, Monitor::_safepoint_check_never); def(Debug3_lock , Mutex , nonleaf+4, true, Monitor::_safepoint_check_never); - def(ProfileVM_lock , Monitor, special, false, Monitor::_safepoint_check_never); // used for profiling of the VMThread def(CompileThread_lock , Monitor, nonleaf+5, false, Monitor::_safepoint_check_always); def(PeriodicTask_lock , Monitor, nonleaf+5, true, Monitor::_safepoint_check_sometimes); if (WhiteBoxAPI) { diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index bbf6f143312..eccd3ca7314 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,6 @@ extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI metho extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers extern Monitor* JNICritical_lock; // a lock used while entering and exiting JNI critical regions, allows GC to sometimes get in extern Mutex* JvmtiThreadState_lock; // a lock on modification of JVMTI thread data -extern Monitor* JvmtiPendingEvent_lock; // a lock on the JVMTI pending events list extern Monitor* Heap_lock; // a lock on the heap extern Mutex* ExpandHeap_lock; // a lock on expanding the heap extern Mutex* AdapterHandlerLibrary_lock; // a lock on the AdapterHandlerLibrary @@ -68,8 +67,6 @@ extern Monitor* CGC_lock; // used for coordination betwee extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet. extern Monitor* SLT_lock; // used in CMS GC for acquiring PLL extern Monitor* FullGCCount_lock; // in support of "concurrent" full gc -extern Monitor* CMark_lock; // used for concurrent mark thread coordination -extern Mutex* CMRegionStack_lock; // used for protecting accesses to the CM region stack extern Mutex* SATB_Q_FL_lock; // Protects SATB Q // buffer free list. extern Monitor* SATB_Q_CBL_mon; // Protects SATB Q @@ -98,8 +95,6 @@ extern Mutex* MultiArray_lock; // a lock used to guard allocat extern Monitor* Terminator_lock; // a lock used to guard termination of the vm extern Monitor* BeforeExit_lock; // a lock used to guard cleanups and shutdown hooks extern Monitor* Notify_lock; // a lock used to synchronize the start-up of the vm -extern Monitor* Interrupt_lock; // a lock used for condition variable mediated interrupt processing -extern Monitor* ProfileVM_lock; // a lock used for profiling the VMThread extern Mutex* ProfilePrint_lock; // a lock used to serialize the printing of profiles extern Mutex* ExceptionCache_lock; // a lock used to synchronize exception cache updates extern Mutex* OsrList_lock; // a lock used to serialize access to OSR queues From c25e32cc70d50a0a9938f75b664ffb3eb887e5e0 Mon Sep 17 00:00:00 2001 From: Christian Tornqvist Date: Wed, 24 Feb 2016 16:34:25 -0500 Subject: [PATCH 059/183] 8150490: Update OS detection code to recognize Windows Server 2016 Reviewed-by: mgronlun, alanb, dholmes --- hotspot/src/os/windows/vm/os_windows.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 19d7319e7e1..72faa4b63a6 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -1668,8 +1668,7 @@ void os::win32::print_windows_version(outputStream* st) { if (is_workstation) { st->print("10"); } else { - // The server version name of Windows 10 is not known at this time - st->print("%d.%d", major_version, minor_version); + st->print("Server 2016"); } break; From 8961912c749a2542a391c7e0946dbb74de7f7b01 Mon Sep 17 00:00:00 2001 From: Derek White Date: Wed, 24 Feb 2016 09:25:39 +0100 Subject: [PATCH 060/183] 8134992: vm/gc/compact/Compact_InternedStrings_Strings failed due to a malloc() failure Reviewed-by: mgerdin, brutisso --- hotspot/src/share/vm/gc/shared/collectedHeap.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp index 9bba8daf55e..f132d75e860 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp @@ -405,7 +405,9 @@ size_t CollectedHeap::max_tlab_size() const { oop CollectedHeap::new_store_pre_barrier(JavaThread* thread, oop new_obj) { // If a previous card-mark was deferred, flush it now. flush_deferred_store_barrier(thread); - if (can_elide_initializing_store_barrier(new_obj)) { + if (can_elide_initializing_store_barrier(new_obj) || + new_obj->is_typeArray()) { + // Arrays of non-references don't need a pre-barrier. // The deferred_card_mark region should be empty // following the flush above. assert(thread->deferred_card_mark().is_empty(), "Error"); From 7234547f04c3496a8985281b538e069eb780b50c Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Wed, 24 Feb 2016 14:36:53 +0300 Subject: [PATCH 061/183] 8081722: Provide public access to sun.awt.shell.ShellFolder methods which are required for implementing javax.swing.JFileChooser Reviewed-by: prr, serb, alexsch --- .../swing/filechooser/FileSystemView.java | 65 +++++++++- .../ShellFolderQueriesTest.java | 122 ++++++++++++++++++ 2 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 jdk/test/javax/swing/JFileChooser/ShellFolderQueries/ShellFolderQueriesTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java b/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java index bbc35bf9c1d..e573cf6f6af 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, 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 @@ -583,6 +583,69 @@ public abstract class FileSystemView { } } + /** + * Returns an array of files representing the values to show by default in + * the file chooser selector. + * + * @return an array of {@code File} objects. + * @throws SecurityException if the caller does not have necessary + * permissions + * @since 9 + */ + public File[] getChooserComboBoxFiles() { + return (File[]) ShellFolder.get("fileChooserComboBoxFolders"); + } + + /** + * Returns whether the specified file denotes a shell interpreted link which + * can be obtained by the {@link #getLinkLocation(File)}. + * + * @param file a file + * @return whether this is a link + * @throws NullPointerException if {@code file} equals {@code null} + * @throws SecurityException if the caller does not have necessary + * permissions + * @see #getLinkLocation(File) + * @since 9 + */ + public boolean isLink(File file) { + if (file == null) { + throw new NullPointerException("file is null"); + } + try { + return ShellFolder.getShellFolder(file).isLink(); + } catch (FileNotFoundException e) { + return false; + } + } + + /** + * Returns the regular file referenced by the specified link file if + * the specified file is a shell interpreted link. + * Returns {@code null} if the specified file is not + * a shell interpreted link. + * + * @param file a file + * @return the linked file or {@code null}. + * @throws FileNotFoundException if the linked file does not exist + * @throws NullPointerException if {@code file} equals {@code null} + * @throws SecurityException if the caller does not have necessary + * permissions + * @since 9 + */ + public File getLinkLocation(File file) throws FileNotFoundException { + if (file == null) { + throw new NullPointerException("file is null"); + } + ShellFolder shellFolder; + try { + shellFolder = ShellFolder.getShellFolder(file); + } catch (FileNotFoundException e) { + return null; + } + return shellFolder.isLink() ? shellFolder.getLinkLocation() : null; + } + /** * Throws {@code FileNotFoundException} if file not found or current thread was interrupted */ diff --git a/jdk/test/javax/swing/JFileChooser/ShellFolderQueries/ShellFolderQueriesTest.java b/jdk/test/javax/swing/JFileChooser/ShellFolderQueries/ShellFolderQueriesTest.java new file mode 100644 index 00000000000..0892b5e2090 --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/ShellFolderQueries/ShellFolderQueriesTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8081722 + * @summary Provide public API for file hierarchy provided by + * sun.awt.shell.ShellFolder + * @author Semyon Sadetsky + * @run main ShellFolderQueriesTest + */ + +import sun.awt.OSInfo; + +import javax.swing.filechooser.FileSystemView; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +public class ShellFolderQueriesTest { + static final String HOME = System.getProperty("user.home"); + static final FileSystemView fsv = FileSystemView.getFileSystemView(); + + + static String scriptBeg = + "set WshShell = WScript.CreateObject(\"WScript.Shell\")\n" + + "set oShellLink = WshShell.CreateShortcut(\"shortcut.lnk\")\n" + + "oShellLink.TargetPath = \""; + static String scriptEnd = "\"\noShellLink.WindowStyle = 1\noShellLink.Save"; + + public static void main(String[] args) throws Exception { + if(OSInfo.getOSType() == OSInfo.OSType.WINDOWS) { + testGet(); + testLink(); + } else { + testGet(); + } + System.out.println("ok"); + } + + private static void testLink() throws IOException, InterruptedException { + // Create and execute VBS script to create a link + File file = createVbsScript(scriptBeg + HOME + scriptEnd); + Runtime.getRuntime().exec("cscript " + file.getName(), null, + file.getParentFile()).waitFor(); + file.delete(); + + File link = new File(file.getParentFile(), "shortcut.lnk"); + if (!fsv.isLink(link)) { + link.delete(); + throw new RuntimeException("Link is not detected"); + } + + File location = fsv.getLinkLocation(link); + if (!location.getAbsolutePath().equals(HOME)) { + link.delete(); + throw new RuntimeException("Link location " + location + + " is wrong"); + } + link.delete(); + + + link = File.createTempFile("test", ".tst"); + + if (fsv.isLink(link)) { + link.delete(); + throw new RuntimeException("File is not a link"); + } + + try { + location = fsv.getLinkLocation(link); + if (location != null) { + link.delete(); + throw new RuntimeException("Not a link, should return null"); + } + } + catch (FileNotFoundException e) { + } + link.delete(); + } + + private static File createVbsScript(String script) throws IOException { + File file = File.createTempFile("test", ".vbs"); + file.deleteOnExit(); + FileOutputStream fos = new FileOutputStream(file); + fos.write(script.getBytes()); + fos.close(); + return file; + } + + private static void testGet() { + File[] files = fsv.getChooserComboBoxFiles(); + for (File file : files) { + if (fsv.isLink(file)) { + throw new RuntimeException( + "Link shouldn't be in FileChooser combobox, " + + file.getPath()); + } + } + } +} From 306361b2920760ba73a4075836b30be8b54066e6 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Mon, 7 Mar 2016 13:45:38 -0500 Subject: [PATCH 062/183] 8139474: -release 7 -verbose causes Javac exception Reviewed-by: jjg --- .../com/sun/tools/javac/code/ClassFinder.java | 27 ++++++++-------- .../sun/tools/javac/file/RelativePath.java | 3 +- .../JavacProcessingEnvironment.java | 15 +++++---- .../T8139474/DashRelease7DashVerboseTest.java | 31 +++++++++++++++++++ 4 files changed, 54 insertions(+), 22 deletions(-) create mode 100644 langtools/test/tools/javac/T8139474/DashRelease7DashVerboseTest.java diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java index 0c602c4c16a..466a41d7635 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/ClassFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ package com.sun.tools.javac.code; import java.io.IOException; -import java.io.File; +import java.nio.file.Path; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; @@ -45,7 +45,6 @@ import com.sun.tools.javac.code.Symbol.CompletionFailure; import com.sun.tools.javac.code.Symbol.PackageSymbol; import com.sun.tools.javac.code.Symbol.TypeSymbol; import com.sun.tools.javac.comp.Annotate; -import com.sun.tools.javac.comp.Enter; import com.sun.tools.javac.file.JRTIndex; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.jvm.ClassReader; @@ -535,25 +534,25 @@ public class ClassFinder { if (fileManager instanceof StandardJavaFileManager) { StandardJavaFileManager fm = (StandardJavaFileManager)fileManager; if (haveSourcePath && wantSourceFiles) { - List path = List.nil(); - for (File file : fm.getLocation(SOURCE_PATH)) { - path = path.prepend(file); + List path = List.nil(); + for (Path sourcePath : fm.getLocationAsPaths(SOURCE_PATH)) { + path = path.prepend(sourcePath); } log.printVerbose("sourcepath", path.reverse().toString()); } else if (wantSourceFiles) { - List path = List.nil(); - for (File file : fm.getLocation(CLASS_PATH)) { - path = path.prepend(file); + List path = List.nil(); + for (Path classPath : fm.getLocationAsPaths(CLASS_PATH)) { + path = path.prepend(classPath); } log.printVerbose("sourcepath", path.reverse().toString()); } if (wantClassFiles) { - List path = List.nil(); - for (File file : fm.getLocation(PLATFORM_CLASS_PATH)) { - path = path.prepend(file); + List path = List.nil(); + for (Path platformPath : fm.getLocationAsPaths(PLATFORM_CLASS_PATH)) { + path = path.prepend(platformPath); } - for (File file : fm.getLocation(CLASS_PATH)) { - path = path.prepend(file); + for (Path classPath : fm.getLocationAsPaths(CLASS_PATH)) { + path = path.prepend(classPath); } log.printVerbose("classpath", path.reverse().toString()); } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RelativePath.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RelativePath.java index 59d79df9ac1..3e541b884f1 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RelativePath.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/RelativePath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, 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 @@ -25,7 +25,6 @@ package com.sun.tools.javac.file; -import java.io.File; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.InvalidPathException; diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 94ed6da8d11..9165f9b2cb9 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -31,6 +31,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URL; +import java.nio.file.Path; import java.util.*; import java.util.regex.*; import java.util.stream.Collectors; @@ -42,6 +43,7 @@ import javax.lang.model.util.*; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; + import static javax.tools.StandardLocation.*; import com.sun.source.util.TaskEvent; @@ -79,6 +81,7 @@ import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Names; import com.sun.tools.javac.util.Options; import com.sun.tools.javac.util.ServiceLoader; + import static com.sun.tools.javac.code.Lint.LintCategory.PROCESSING; import static com.sun.tools.javac.code.Kinds.Kind.*; import static com.sun.tools.javac.main.Option.*; @@ -317,9 +320,9 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea if (fileManager instanceof JavacFileManager) { StandardJavaFileManager standardFileManager = (JavacFileManager) fileManager; - Iterable workingPath = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH) - ? standardFileManager.getLocation(ANNOTATION_PROCESSOR_PATH) - : standardFileManager.getLocation(CLASS_PATH); + Iterable workingPath = fileManager.hasLocation(ANNOTATION_PROCESSOR_PATH) + ? standardFileManager.getLocationAsPaths(ANNOTATION_PROCESSOR_PATH) + : standardFileManager.getLocationAsPaths(CLASS_PATH); if (needClassLoader(options.get(PROCESSOR), workingPath) ) handleException(key, e); @@ -1298,14 +1301,14 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea * Called retroactively to determine if a class loader was required, * after we have failed to create one. */ - private boolean needClassLoader(String procNames, Iterable workingpath) { + private boolean needClassLoader(String procNames, Iterable workingpath) { if (procNames != null) return true; URL[] urls = new URL[1]; - for(File pathElement : workingpath) { + for(Path pathElement : workingpath) { try { - urls[0] = pathElement.toURI().toURL(); + urls[0] = pathElement.toUri().toURL(); if (ServiceProxy.hasService(Processor.class, urls)) return true; } catch (MalformedURLException ex) { diff --git a/langtools/test/tools/javac/T8139474/DashRelease7DashVerboseTest.java b/langtools/test/tools/javac/T8139474/DashRelease7DashVerboseTest.java new file mode 100644 index 00000000000..5e0c19cddb3 --- /dev/null +++ b/langtools/test/tools/javac/T8139474/DashRelease7DashVerboseTest.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * bug 8139474 + * @summary -release 7 -verbose causes Javac exception + * @compile -release 7 -verbose DashRelease7DashVerboseTest.java +*/ + +public class DashRelease7DashVerboseTest {} From 528c1dfc4ee4a8b2d98395949ccddf0b35d72f87 Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Tue, 8 Mar 2016 11:37:00 -0800 Subject: [PATCH 063/183] 8148187: Remove OS X-specific com.apple.concurrent package Removed jdk.deploy.osx module (including com.apple.concurrent) Reviewed-by: alanb, erikj, mchung --- .../share/classes/com/sun/tools/javac/resources/ct.properties | 1 - .../jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/ct.properties b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/ct.properties index 135646a3fdb..b94ead7665b 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/ct.properties +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/ct.properties @@ -1,6 +1,5 @@ apple.laf.*: hidden apple.security.*: hidden -com.apple.concurrent.*: hidden com.apple.eawt.*: hidden com.apple.eawt.event.*: hidden com.apple.eio.*: hidden diff --git a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java index bd70ec841b1..1c45a2fd54f 100644 --- a/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java +++ b/langtools/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Profile.java @@ -38,7 +38,7 @@ enum Profile { "jdk.httpserver", "jdk.security.auth", "jdk.naming.dns", "jdk.naming.rmi", "jdk.management"), - FULL_JRE("Full JRE", 4, "java.se", "jdk.deploy.osx", "jdk.charsets", + FULL_JRE("Full JRE", 4, "java.se", "jdk.charsets", "jdk.crypto.ec", "jdk.crypto.pkcs11", "jdk.crypto.mscapi", "jdk.crypto.ucrypto", "jdk.jvmstat", "jdk.localedata", "jdk.scripting.nashorn", "jdk.zipfs"); From 51ea08084f757c2f33b9815a97b4328a3b64b1dc Mon Sep 17 00:00:00 2001 From: Robert Field Date: Tue, 8 Mar 2016 11:53:35 -0800 Subject: [PATCH 064/183] 8148316: jshell tool: Configurable output format 8148317: jshell tool: unify commands into /set 8149524: JShell: CompletenessAnalysis fails on class Case, E2 extends Enum, E3 extends Enum> {} Reviewed-by: jlahoda --- .../internal/jshell/tool/ArgTokenizer.java | 271 +++++ .../jdk/internal/jshell/tool/Feedback.java | 1049 +++++++++++++++++ .../jdk/internal/jshell/tool/JShellTool.java | 778 ++++++------ .../jdk/jshell/CompletenessAnalyzer.java | 4 +- .../jdk/jshell/CommandCompletionTest.java | 8 +- .../test/jdk/jshell/CompletenessTest.java | 4 +- .../test/jdk/jshell/ExternalEditorTest.java | 8 +- .../test/jdk/jshell/ReplToolTesting.java | 43 +- langtools/test/jdk/jshell/ToolBasicTest.java | 97 +- langtools/test/jdk/jshell/ToolFormatTest.java | 159 +++ 10 files changed, 1996 insertions(+), 425 deletions(-) create mode 100644 langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java create mode 100644 langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java create mode 100644 langtools/test/jdk/jshell/ToolFormatTest.java diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java new file mode 100644 index 00000000000..2e86d9de290 --- /dev/null +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java @@ -0,0 +1,271 @@ +/* + * Copyright (c) 1995, 2016, 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 jdk.internal.jshell.tool; + +import java.util.Arrays; +import java.util.stream.Stream; + +/** + * Parse command arguments, derived from StreamTokenizer by + * @author James Gosling + */ +class ArgTokenizer { + + private final String str; + private final int length; + private int next = 0; + private char buf[] = new char[20]; + private int mark; + + private final byte ctype[] = new byte[256]; + private static final byte CT_ALPHA = 0; + private static final byte CT_WHITESPACE = 1; + private static final byte CT_QUOTE = 8; + + private String sval; + private boolean isQuoted = false; + + ArgTokenizer(String arg) { + this.str = arg; + this.length = arg.length(); + quoteChar('"'); + quoteChar('\''); + whitespaceChars(0x09, 0x0D); + whitespaceChars(0x1C, 0x20); + whitespaceChars(0x85, 0x85); + whitespaceChars(0xA0, 0xA0); + } + + String next() { + nextToken(); + return sval; + } + + String[] next(String... strings) { + return next(Arrays.stream(strings)); + } + + String[] next(Stream stream) { + nextToken(); + if (sval == null) { + return null; + } + String[] matches = stream + .filter(s -> s.startsWith(sval)) + .toArray(size -> new String[size]); + return matches; + } + + String val() { + return sval; + } + + boolean isQuoted() { + return isQuoted; + } + + String whole() { + return str; + } + + void mark() { + mark = next; + } + + void rewind() { + next = mark; + } + + /** + * Reads a single character. + * + * @return The character read, or -1 if the end of the stream has been + * reached + */ + private int read() { + if (next >= length) { + return -1; + } + return str.charAt(next++); + } + + /** + * Specifies that all characters c in the range + * low <= c <= high + * are white space characters. White space characters serve only to + * separate tokens in the input stream. + * + *

Any other attribute settings for the characters in the specified + * range are cleared. + * + * @param low the low end of the range. + * @param hi the high end of the range. + */ + private void whitespaceChars(int low, int hi) { + if (low < 0) + low = 0; + if (hi >= ctype.length) + hi = ctype.length - 1; + while (low <= hi) + ctype[low++] = CT_WHITESPACE; + } + + /** + * Specifies that matching pairs of this character delimit string + * constants in this tokenizer. + *

+ * If a string quote character is encountered, then a string is + * recognized, consisting of all characters after (but not including) + * the string quote character, up to (but not including) the next + * occurrence of that same string quote character, or a line + * terminator, or end of file. The usual escape sequences such as + * {@code "\u005Cn"} and {@code "\u005Ct"} are recognized and + * converted to single characters as the string is parsed. + * + *

Any other attribute settings for the specified character are cleared. + * + * @param ch the character. + */ + private void quoteChar(int ch) { + if (ch >= 0 && ch < ctype.length) + ctype[ch] = CT_QUOTE; + } + + private int unicode2ctype(int c) { + switch (c) { + case 0x1680: + case 0x180E: + case 0x200A: + case 0x202F: + case 0x205F: + case 0x3000: + return CT_WHITESPACE; + default: + return CT_ALPHA; + } + } + + /** + * Parses the next token of this tokenizer. + */ + public void nextToken() { + byte ct[] = ctype; + int c; + int lctype; + sval = null; + isQuoted = false; + + do { + c = read(); + if (c < 0) { + return; + } + lctype = (c < 256) ? ct[c] : unicode2ctype(c); + } while (lctype == CT_WHITESPACE); + + if (lctype == CT_ALPHA) { + int i = 0; + do { + if (i >= buf.length) { + buf = Arrays.copyOf(buf, buf.length * 2); + } + buf[i++] = (char) c; + c = read(); + lctype = c < 0 ? CT_WHITESPACE : (c < 256)? ct[c] : unicode2ctype(c); + } while (lctype == CT_ALPHA); + if (c >= 0) --next; // push last back + sval = String.copyValueOf(buf, 0, i); + return; + } + + if (lctype == CT_QUOTE) { + int quote = c; + int i = 0; + /* Invariants (because \Octal needs a lookahead): + * (i) c contains char value + * (ii) d contains the lookahead + */ + int d = read(); + while (d >= 0 && d != quote) { + if (d == '\\') { + c = read(); + int first = c; /* To allow \377, but not \477 */ + if (c >= '0' && c <= '7') { + c = c - '0'; + int c2 = read(); + if ('0' <= c2 && c2 <= '7') { + c = (c << 3) + (c2 - '0'); + c2 = read(); + if ('0' <= c2 && c2 <= '7' && first <= '3') { + c = (c << 3) + (c2 - '0'); + d = read(); + } else + d = c2; + } else + d = c2; + } else { + switch (c) { + case 'a': + c = 0x7; + break; + case 'b': + c = '\b'; + break; + case 'f': + c = 0xC; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'v': + c = 0xB; + break; + } + d = read(); + } + } else { + c = d; + d = read(); + } + if (i >= buf.length) { + buf = Arrays.copyOf(buf, buf.length * 2); + } + buf[i++] = (char)c; + } + + if (d == quote) { + isQuoted = true; + } + sval = String.copyValueOf(buf, 0, i); + } + } +} diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java new file mode 100644 index 00000000000..9089dfc86aa --- /dev/null +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java @@ -0,0 +1,1049 @@ +/* + * Copyright (c) 2016, 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 jdk.internal.jshell.tool; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Feedback customization support + * + * @author Robert Field + */ +class Feedback { + + // Patern for substituted fields within a customized format string + private static final Pattern FIELD_PATTERN = Pattern.compile("\\{(.*?)\\}"); + + // Current mode + private Mode mode = new Mode("", false); // initial value placeholder during start-up + + // Mapping of mode names to mode modes + private final Map modeMap = new HashMap<>(); + + public boolean shouldDisplayCommandFluff() { + return mode.commandFluff; + } + + public String getPre() { + return mode.pre; + } + + public String getPost() { + return mode.post; + } + + public String getErrorPre() { + return mode.errorPre; + } + + public String getErrorPost() { + return mode.errorPost; + } + + public String getFormat(FormatCase fc, FormatWhen fw, FormatAction fa, FormatResolve fr, + boolean hasName, boolean hasType, boolean hasResult) { + return mode.getFormat(fc, fw, fa, fr, hasName, hasType, hasResult); + } + + public String getPrompt(String nextId) { + return mode.getPrompt(nextId); + } + + public String getContinuationPrompt(String nextId) { + return mode.getContinuationPrompt(nextId); + } + + public boolean setFeedback(JShellTool tool, ArgTokenizer at) { + return new FormatSetter(tool, at).setFeedback(); + } + + public boolean setField(JShellTool tool, ArgTokenizer at) { + return new FormatSetter(tool, at).setField(); + } + + public boolean setFormat(JShellTool tool, ArgTokenizer at) { + return new FormatSetter(tool, at).setFormat(); + } + + public boolean setNewMode(JShellTool tool, ArgTokenizer at) { + return new FormatSetter(tool, at).setNewMode(); + } + + public boolean setPrompt(JShellTool tool, ArgTokenizer at) { + return new FormatSetter(tool, at).setPrompt(); + } + + public void printFeedbackHelp(JShellTool tool) { + new FormatSetter(tool, null).printFeedbackHelp(); + } + + public void printFieldHelp(JShellTool tool) { + new FormatSetter(tool, null).printFieldHelp(); + } + + public void printFormatHelp(JShellTool tool) { + new FormatSetter(tool, null).printFormatHelp(); + } + + public void printNewModeHelp(JShellTool tool) { + new FormatSetter(tool, null).printNewModeHelp(); + } + + public void printPromptHelp(JShellTool tool) { + new FormatSetter(tool, null).printPromptHelp(); + } + + /** + * Holds all the context of a mode mode + */ + private class Mode { + + // Use name of mode mode + + final String name; + + // Display command verification/information + final boolean commandFluff; + + // event cases: class, method + final EnumMap>> cases; + + // action names: add. modified, replaced, ... + final EnumMap> actions; + + // resolution status description format with %s for unresolved + final EnumMap> resolves; + + // primary snippet vs update + final EnumMap whens; + + // fixed map of how to get format string for a field, given a specific formatting contet + final EnumMap> fields; + + // format wrappers for name, type, and result + String fname = "%s"; + String ftype = "%s"; + String fresult = "%s"; + + // start and end, also used by hard-coded output + String pre = "| "; + String post = "\n"; + String errorPre = "| Error: "; + String errorPost = "\n"; + + String prompt = "\n-> "; + String continuationPrompt = ">> "; + + /** + * The context of a specific mode to potentially display. + */ + class Context { + + final FormatCase fc; + final FormatAction fa; + final FormatResolve fr; + final FormatWhen fw; + final boolean hasName; + final boolean hasType; + final boolean hasResult; + + Context(FormatCase fc, FormatWhen fw, FormatAction fa, FormatResolve fr, + boolean hasName, boolean hasType, boolean hasResult) { + this.fc = fc; + this.fa = fa; + this.fr = fr; + this.fw = fw; + this.hasName = hasName; + this.hasType = hasType; + this.hasResult = hasResult; + } + + String when() { + return whens.get(fw); + } + + String action() { + return actions.get(fa).get(fw); + } + + String resolve() { + return String.format(resolves.get(fr).get(fw), FormatField.RESOLVE.form); + } + + String name() { + return hasName + ? String.format(fname, FormatField.NAME.form) + : ""; + } + + String type() { + return hasType + ? String.format(ftype, FormatField.TYPE.form) + : ""; + } + + String result() { + return hasResult + ? String.format(fresult, FormatField.RESULT.form) + : ""; + } + + /** + * Lookup format based on case, action, and whether it update. + * Replace fields with context specific formats. + * + * @return format string + */ + String format() { + String format = cases.get(fc).get(fa).get(fw); + if (format == null) { + return ""; + } + Matcher m = FIELD_PATTERN.matcher(format); + StringBuffer sb = new StringBuffer(format.length()); + while (m.find()) { + String fieldName = m.group(1).toUpperCase(Locale.US); + String sub = null; + for (FormatField f : FormatField.values()) { + if (f.name().startsWith(fieldName)) { + sub = fields.get(f).apply(this); + break; + } + } + if (sub != null) { + m.appendReplacement(sb, Matcher.quoteReplacement(sub)); + } + } + m.appendTail(sb); + return sb.toString(); + } + } + + { + // set fixed mappings of fields + fields = new EnumMap<>(FormatField.class); + fields.put(FormatField.WHEN, c -> c.when()); + fields.put(FormatField.ACTION, c -> c.action()); + fields.put(FormatField.RESOLVE, c -> c.resolve()); + fields.put(FormatField.NAME, c -> c.name()); + fields.put(FormatField.TYPE, c -> c.type()); + fields.put(FormatField.RESULT, c -> c.result()); + fields.put(FormatField.PRE, c -> pre); + fields.put(FormatField.POST, c -> post); + fields.put(FormatField.ERRORPRE, c -> errorPre); + fields.put(FormatField.ERRORPOST, c -> errorPost); + } + + /** + * Set up an empty mode. + * + * @param name + * @param commandFluff True if should display command fluff messages + */ + Mode(String name, boolean commandFluff) { + this.name = name; + this.commandFluff = commandFluff; + cases = new EnumMap<>(FormatCase.class); + for (FormatCase fc : FormatCase.values()) { + EnumMap> ac = new EnumMap<>(FormatAction.class); + cases.put(fc, ac); + for (FormatAction fa : FormatAction.values()) { + EnumMap aw = new EnumMap<>(FormatWhen.class); + ac.put(fa, aw); + for (FormatWhen fw : FormatWhen.values()) { + aw.put(fw, ""); + } + } + } + + actions = new EnumMap<>(FormatAction.class); + for (FormatAction fa : FormatAction.values()) { + EnumMap afw = new EnumMap<>(FormatWhen.class); + actions.put(fa, afw); + for (FormatWhen fw : FormatWhen.values()) { + afw.put(fw, fa.name() + "-" + fw.name()); + } + } + + resolves = new EnumMap<>(FormatResolve.class); + for (FormatResolve fr : FormatResolve.values()) { + EnumMap arw = new EnumMap<>(FormatWhen.class); + resolves.put(fr, arw); + for (FormatWhen fw : FormatWhen.values()) { + arw.put(fw, fr.name() + "-" + fw.name() + ": %s"); + } + } + + whens = new EnumMap<>(FormatWhen.class); + for (FormatWhen fw : FormatWhen.values()) { + whens.put(fw, fw.name()); + } + } + + /** + * Set up a copied mode. + * + * @param name + * @param commandFluff True if should display command fluff messages + * @param m Mode to copy + */ + Mode(String name, boolean commandFluff, Mode m) { + this.name = name; + this.commandFluff = commandFluff; + cases = new EnumMap<>(FormatCase.class); + for (FormatCase fc : FormatCase.values()) { + EnumMap> ac = new EnumMap<>(FormatAction.class); + EnumMap> mc = m.cases.get(fc); + cases.put(fc, ac); + for (FormatAction fa : FormatAction.values()) { + EnumMap aw = new EnumMap<>(mc.get(fa)); + ac.put(fa, aw); + } + } + + actions = new EnumMap<>(FormatAction.class); + for (FormatAction fa : FormatAction.values()) { + EnumMap afw = new EnumMap<>(m.actions.get(fa)); + actions.put(fa, afw); + } + + resolves = new EnumMap<>(FormatResolve.class); + for (FormatResolve fr : FormatResolve.values()) { + EnumMap arw = new EnumMap<>(m.resolves.get(fr)); + resolves.put(fr, arw); + } + + whens = new EnumMap<>(m.whens); + + this.fname = m.fname; + this.ftype = m.ftype; + this.fresult = m.fresult; + this.pre = m.pre; + this.post = m.post; + this.errorPre = m.errorPre; + this.errorPost = m.errorPost; + this.prompt = m.prompt; + this.continuationPrompt = m.continuationPrompt; + } + + String getFormat(FormatCase fc, FormatWhen fw, FormatAction fa, FormatResolve fr, + boolean hasName, boolean hasType, boolean hasResult) { + Context context = new Context(fc, fw, fa, fr, + hasName, hasType, hasResult); + return context.format(); + } + + void setCases(String format, Collection cc, Collection ca, Collection cw) { + for (FormatCase fc : cc) { + EnumMap> ma = cases.get(fc); + for (FormatAction fa : ca) { + EnumMap mw = ma.get(fa); + for (FormatWhen fw : cw) { + mw.put(fw, format); + } + } + } + } + + void setActions(String format, Collection ca, Collection cw) { + for (FormatAction fa : ca) { + EnumMap mw = actions.get(fa); + for (FormatWhen fw : cw) { + mw.put(fw, format); + } + } + } + + void setResolves(String format, Collection cr, Collection cw) { + for (FormatResolve fr : cr) { + EnumMap mw = resolves.get(fr); + for (FormatWhen fw : cw) { + mw.put(fw, format); + } + } + } + + void setWhens(String format, Collection cw) { + for (FormatWhen fw : cw) { + whens.put(fw, format); + } + } + + void setName(String s) { + fname = s; + } + + void setType(String s) { + ftype = s; + } + + void setResult(String s) { + fresult = s; + } + + void setPre(String s) { + pre = s; + } + + void setPost(String s) { + post = s; + } + + void setErrorPre(String s) { + errorPre = s; + } + + void setErrorPost(String s) { + errorPost = s; + } + + String getPre() { + return pre; + } + + String getPost() { + return post; + } + + String getErrorPre() { + return errorPre; + } + + String getErrorPost() { + return errorPost; + } + + void setPrompts(String prompt, String continuationPrompt) { + this.prompt = prompt; + this.continuationPrompt = continuationPrompt; + } + + String getPrompt(String nextId) { + return String.format(prompt, nextId); + } + + String getContinuationPrompt(String nextId) { + return String.format(continuationPrompt, nextId); + } + } + + /** + * The brace delimited substitutions + */ + public enum FormatField { + WHEN, + ACTION, + RESOLVE("%1$s"), + NAME("%2$s"), + TYPE("%3$s"), + RESULT("%4$s"), + PRE, + POST, + ERRORPRE, + ERRORPOST; + String form; + + FormatField(String s) { + this.form = s; + } + + FormatField() { + this.form = null; + } + } + + /** + * The event cases + */ + public enum FormatCase { + IMPORT("import declaration: {action} {name}"), + CLASS("class, interface, enum, or annotation declaration: {action} {name} {resolve}"), + INTERFACE("class, interface, enum, or annotation declaration: {action} {name} {resolve}"), + ENUM("class, interface, enum, or annotation declaration: {action} {name} {resolve}"), + ANNOTATION("annotation interface declaration: {action} {name} {resolve}"), + METHOD("method declaration: {action} {name} {type}==parameter-types {resolve}"), + VARDECL("variable declaration: {action} {name} {type} {resolve}"), + VARDECLRECOVERABLE("recoverably failed variable declaration: {action} {name} {resolve}"), + VARINIT("variable declaration with init: {action} {name} {type} {resolve} {result}"), + VARRESET("variable reset on update: {action} {name}"), + EXPRESSION("expression: {action}=='Saved to scratch variable' {name} {type} {result}"), + VARVALUE("variable value expression: {action} {name} {type} {result}"), + ASSIGNMENT("assign variable: {action} {name} {type} {result}"), + STATEMENT("statement: {action}"); + String doc; + + private FormatCase(String doc) { + this.doc = doc; + } + } + + /** + * The event actions + */ + public enum FormatAction { + ADDED("snippet has been added"), + MODIFIED("an existing snippet has been modified"), + REPLACED("an existing snippet has been replaced with a new snippet"), + OVERWROTE("an existing snippet has been overwritten"), + DROPPED("snippet has been dropped"), + REJECTED("snippet has failed and been rejected"); + String doc; + + private FormatAction(String doc) { + this.doc = doc; + } + } + + /** + * When the event occurs: primary or update + */ + public enum FormatWhen { + PRIMARY("the entered snippet"), + UPDATE("an update to a dependent snippet"); + String doc; + + private FormatWhen(String doc) { + this.doc = doc; + } + } + + /** + * Resolution problems with event + */ + public enum FormatResolve { + OK("resolved correctly"), + DEFINED("defined despite recoverably unresolved references"), + NOTDEFINED("not defined because of recoverably unresolved references"); + String doc; + + private FormatResolve(String doc) { + this.doc = doc; + } + } + + // Class used to set custom eval output formats + // For both /set format and /set field -- Parse arguments, setting custom format, or printing error + private class FormatSetter { + + private final ArgTokenizer at; + private final JShellTool tool; + boolean valid = true; + + class Case, E2 extends Enum, E3 extends Enum> { + + Set e1; + Set e2; + Set e3; + + Case(Set e1, Set e2, Set e3) { + this.e1 = e1; + this.e2 = e2; + this.e3 = e3; + } + + Case(Set e1, Set e2) { + this.e1 = e1; + this.e2 = e2; + } + } + + FormatSetter(JShellTool tool, ArgTokenizer at) { + this.tool = tool; + this.at = at; + } + + void hard(String format, Object... args) { + tool.hard(format, args); + } + + > void hardEnums(EnumSet es, Function e2s) { + hardPairs(es.stream(), ev -> ev.name().toLowerCase(Locale.US), e2s); + } + + void hardPairs(Stream stream, Function a, Function b) { + tool.hardPairs(stream, a, b); + } + + void fluff(String format, Object... args) { + tool.fluff(format, args); + } + + void error(String format, Object... args) { + tool.error(format, args); + } + + void errorat(String format, Object... args) { + Object[] a2 = Arrays.copyOf(args, args.length + 1); + a2[args.length] = at.whole(); + tool.error(format + " -- /set %s", a2); + } + + void fluffRaw(String format, Object... args) { + tool.fluffRaw(format, args); + } + + // For /set prompt "" "" + boolean setPrompt() { + Mode m = nextMode(); + String prompt = nextFormat(); + String continuationPrompt = nextFormat(); + if (valid) { + m.setPrompts(prompt, continuationPrompt); + } else { + fluff("See '/help /set prompt' for help"); + } + return valid; + } + + // For /set newmode [command|quiet []] + boolean setNewMode() { + String umode = at.next(); + if (umode == null) { + errorat("Expected new feedback mode"); + valid = false; + } + if (modeMap.containsKey(umode)) { + errorat("Expected a new feedback mode name. %s is a known feedback mode", umode); + valid = false; + } + String[] fluffOpt = at.next("command", "quiet"); + boolean fluff = fluffOpt == null || fluffOpt.length != 1 || "command".equals(fluffOpt[0]); + if (fluffOpt != null && fluffOpt.length != 1) { + errorat("Specify either 'command' or 'quiet'"); + valid = false; + } + Mode om = null; + String omode = at.next(); + if (omode != null) { + om = toMode(omode); + } + if (valid) { + Mode nm = (om != null) + ? new Mode(umode, fluff, om) + : new Mode(umode, fluff); + modeMap.put(umode, nm); + fluff("Created new feedback mode: %s", nm.name); + } else { + fluff("See '/help /set newmode' for help"); + } + return valid; + } + + // For /set feedback + boolean setFeedback() { + Mode m = nextMode(); + if (valid && m != null) { + mode = m; + fluff("Feedback mode: %s", mode.name); + } else { + fluff("See '/help /set feedback' for help"); + } + return valid; + } + + // For /set format "" ... + boolean setFormat() { + Mode m = nextMode(); + String format = nextFormat(); + if (valid) { + List> specs = new ArrayList<>(); + String s; + while ((s = at.next()) != null) { + String[] d = s.split("-"); + specs.add(new Case<>( + parseFormatCase(d, 0), + parseFormatAction(d, 1), + parseFormatWhen(d, 2) + )); + } + if (valid && specs.isEmpty()) { + errorat("At least one selector required"); + valid = false; + } + if (valid) { + // set the format in the specified cases + specs.stream() + .forEach(c -> m.setCases(format, c.e1, c.e2, c.e3)); + } + } + if (!valid) { + fluff("See '/help /set format' for help"); + } + return valid; + } + + // For /set field mode "" ... + boolean setField() { + Mode m = nextMode(); + String fieldName = at.next(); + FormatField field = parseFormatSelector(fieldName, EnumSet.allOf(FormatField.class), "field"); + String format = nextFormat(); + if (valid) { + switch (field) { + case ACTION: { + List> specs = new ArrayList<>(); + String s; + while ((s = at.next()) != null) { + String[] d = s.split("-"); + specs.add(new Case<>( + parseFormatAction(d, 0), + parseFormatWhen(d, 1) + )); + } + if (valid && specs.isEmpty()) { + errorat("At least one selector required"); + valid = false; + } + if (valid) { + // set the format of the specified actions + specs.stream() + .forEach(c -> m.setActions(format, c.e1, c.e2)); + } + break; + } + case RESOLVE: { + List> specs = new ArrayList<>(); + String s; + while ((s = at.next()) != null) { + String[] d = s.split("-"); + specs.add(new Case<>( + parseFormatResolve(d, 0), + parseFormatWhen(d, 1) + )); + } + if (valid && specs.isEmpty()) { + errorat("At least one selector required"); + valid = false; + } + if (valid) { + // set the format of the specified resolves + specs.stream() + .forEach(c -> m.setResolves(format, c.e1, c.e2)); + } + break; + } + case WHEN: { + List> specs = new ArrayList<>(); + String s; + while ((s = at.next()) != null) { + String[] d = s.split("-"); + specs.add(new Case<>( + parseFormatWhen(d, 1), + null + )); + } + if (valid && specs.isEmpty()) { + errorat("At least one selector required"); + valid = false; + } + if (valid) { + // set the format of the specified whens + specs.stream() + .forEach(c -> m.setWhens(format, c.e1)); + } + break; + } + case NAME: { + m.setName(format); + break; + } + case TYPE: { + m.setType(format); + break; + } + case RESULT: { + m.setResult(format); + break; + } + case PRE: { + m.setPre(format); + break; + } + case POST: { + m.setPost(format); + break; + } + case ERRORPRE: { + m.setErrorPre(format); + break; + } + case ERRORPOST: { + m.setErrorPost(format); + break; + } + } + } + if (!valid) { + fluff("See '/help /set field' for help"); + } + return valid; + } + + Mode nextMode() { + String umode = at.next(); + return toMode(umode); + } + + Mode toMode(String umode) { + if (umode == null) { + errorat("Expected a feedback mode"); + valid = false; + return null; + } + Mode m = modeMap.get(umode); + if (m != null) { + return m; + } + // Failing an exact match, go searching + Mode[] matches = modeMap.entrySet().stream() + .filter(e -> e.getKey().startsWith(umode)) + .map(e -> e.getValue()) + .toArray(size -> new Mode[size]); + if (matches.length == 1) { + return matches[0]; + } else { + valid = false; + if (matches.length == 0) { + errorat("Does not match any current feedback mode: %s", umode); + } else { + errorat("Matchs more then one current feedback mode: %s", umode); + } + fluff("The feedback mode should be one of the following:"); + modeMap.keySet().stream() + .forEach(mk -> fluff(" %s", mk)); + fluff("You may also use just enough letters to make it unique."); + return null; + } + } + + // Test if the format string is correctly + final String nextFormat() { + String format = at.next(); + if (format == null) { + errorat("Expected format missing"); + valid = false; + return null; + } + if (!at.isQuoted()) { + errorat("Format '%s' must be quoted", format); + valid = false; + return null; + } + return format; + } + + final Set parseFormatCase(String[] s, int i) { + return parseFormatSelectorStar(s, i, FormatCase.class, EnumSet.allOf(FormatCase.class), "case"); + } + + final Set parseFormatAction(String[] s, int i) { + return parseFormatSelectorStar(s, i, FormatAction.class, + EnumSet.of(FormatAction.ADDED, FormatAction.MODIFIED, FormatAction.REPLACED), "action"); + } + + final Set parseFormatResolve(String[] s, int i) { + return parseFormatSelectorStar(s, i, FormatResolve.class, + EnumSet.of(FormatResolve.DEFINED, FormatResolve.NOTDEFINED), "resolve"); + } + + final Set parseFormatWhen(String[] s, int i) { + return parseFormatSelectorStar(s, i, FormatWhen.class, EnumSet.of(FormatWhen.PRIMARY), "when"); + } + + /** + * In a selector x-y-z , parse x, y, or z -- whether they are missing, + * or a comma separated list of identifiers and stars. + * + * @param The enum this selector should belong to + * @param sa The array of selector strings + * @param i The index of which selector string to use + * @param klass The class of the enum that should be used + * @param defaults The set of enum values to use if the selector is + * missing + * @return The set of enum values specified by this selector + */ + final > Set parseFormatSelectorStar(String[] sa, int i, Class klass, EnumSet defaults, String label) { + String s = sa.length > i + ? sa[i] + : null; + if (s == null || s.isEmpty()) { + return defaults; + } + Set set = EnumSet.noneOf(klass); + EnumSet values = EnumSet.allOf(klass); + for (String as : s.split(",")) { + if (as.equals("*")) { + set.addAll(values); + } else if (!as.isEmpty()) { + set.add(parseFormatSelector(as, values, label)); + } + } + return set; + } + + /** + * In a x-y-a,b selector, parse an x, y, a, or b -- that is an + * identifier + * + * @param The enum this selector should belong to + * @param s The string to parse: x, y, or z + * @param values The allowed of this enum + * @return The enum value + */ + final > E parseFormatSelector(String s, EnumSet values, String label) { + if (s == null) { + valid = false; + return null; + } + String u = s.toUpperCase(Locale.US); + for (E c : values) { + if (c.name().startsWith(u)) { + return c; + } + } + + errorat("Not a valid %s: %s, must be one of: %s", label, s, + values.stream().map(v -> v.name().toLowerCase(Locale.US)).collect(Collectors.joining(" "))); + valid = false; + return values.iterator().next(); + } + + final void printFormatHelp() { + hard("Set the format for reporting a snippet event."); + hard(""); + hard("/set format \"\" ..."); + hard(""); + hard("Where is the name of a previously defined feedback mode -- see '/help /set newmode'."); + hard("Where is a quoted string which will have these field substitutions:"); + hard(" {action} == The action, e.g.: Added, Modified, Assigned, ..."); + hard(" {name} == The name, e.g.: the variable name, ..."); + hard(" {type} == The type name"); + hard(" {resolve} == Unresolved info, e.g.: ', however, it cannot be invoked until'"); + hard(" {result} == The result value"); + hard(" {when} == The entered snippet or a resultant update"); + hard(" {pre} == The feedback prefix"); + hard(" {post} == The feedback postfix"); + hard(" {errorpre} == The error prefix"); + hard(" {errorpost} == The error postfix"); + hard("Use '/set field' to set the format of these substitutions."); + hard("Where is the context in which the format is applied."); + hard("The structure of selector is: [-[-]]"); + hard("Where each field component may be missing (indicating defaults),"); + hard("star (indicating all), or a comma separated list of field values."); + hard("For case, the field values are:"); + hardEnums(EnumSet.allOf(FormatCase.class), ev -> ev.doc); + hard("For action, the field values are:"); + hardEnums(EnumSet.allOf(FormatAction.class), ev -> ev.doc); + hard("For when, the field values are:"); + hardEnums(EnumSet.allOf(FormatWhen.class), ev -> ev.doc); + hard(""); + hard("Example:"); + hard(" /set format example '{pre}{action} variable {name}, reset to null{post}' varreset-*-update"); + } + + final void printFieldHelp() { + hard("Set the format of a field substitution as used in '/set format'."); + hard(""); + hard("/set field \"\" ..."); + hard(""); + hard("Where is the name of a previously defined feedback mode -- see '/set newmode'."); + hard("Where is context-specific format to set, each with its own selector structure:"); + hard(" action == The action. The selector: -."); + hard(" name == The name. '%%s' is the name. No selectors."); + hard(" type == The type name. '%%s' is the type. No selectors."); + hard(" resolve == Unresolved info. '%%s' is the unresolved list. The selector: -."); + hard(" result == The result value. '%%s' is the result value. No selectors."); + hard(" when == The entered snippet or a resultant update. The selector: "); + hard(" pre == The feedback prefix. No selectors."); + hard(" post == The feedback postfix. No selectors."); + hard(" errorpre == The error prefix. No selectors."); + hard(" errorpost == The error postfix. No selectors."); + hard("Where is a quoted string -- see the description specific to the field (above)."); + hard("Where is the context in which the format is applied (see above)."); + hard("For action, the field values are:"); + hardEnums(EnumSet.allOf(FormatAction.class), ev -> ev.doc); + hard("For when, the field values are:"); + hardEnums(EnumSet.allOf(FormatWhen.class), ev -> ev.doc); + hard("For resolve, the field values are:"); + hardEnums(EnumSet.allOf(FormatResolve.class), ev -> ev.doc); + hard(""); + hard("Example:"); + hard(" /set field example resolve ' which cannot be invoked until%%s is declared' defined-update"); + } + + final void printFeedbackHelp() { + hard("Set the feedback mode describing displayed feedback for entered snippets and commands."); + hard(""); + hard("/set feedback "); + hard(""); + hard("Where is the name of a previously defined feedback mode."); + hard("Currently defined feedback modes:"); + modeMap.keySet().stream() + .forEach(m -> hard(" %s", m)); + hard("User-defined modes can be added, see '/help /set newmode'"); + } + + final void printNewModeHelp() { + hard("Create a user-defined feedback mode, optionally copying from an existing mode."); + hard(""); + hard("/set newmode [command|quiet []]"); + hard(""); + hard("Where is the name of a mode you wish to create."); + hard("Where is the name of a previously defined feedback mode."); + hard("If is present, its settings are copied to the new mode."); + hard("'command' vs 'quiet' determines if informative/verifying command feedback is displayed."); + hard(""); + hard("Once the new mode is created, use '/set format', '/set field', and '/set prompt' to configure it."); + hard("Use '/set feedback' to use the new mode."); + } + + final void printPromptHelp() { + hard("Set the prompts. Both the normal prompt and the continuation-prompt must be set."); + hard(""); + hard("/set prompt \"\" \"\""); + hard(""); + hard("Where is the name of a previously defined feedback mode."); + hard("Where and are quoted strings printed as input promptds;"); + hard("Both may optionally contain '%%s' which will be substituted with the next snippet id --"); + hard("note that what is entered may not be assigned that id, for example it may be an error or command."); + hard("The continuation-prompt is used on the second and subsequent lines of a multi-line snippet."); + } + } +} diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java index fd14be2a612..10b121b4062 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -1,6 +1,5 @@ - /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +34,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.io.Reader; -import java.io.StreamTokenizer; import java.io.StringReader; import java.nio.charset.Charset; import java.nio.file.AccessDeniedException; @@ -66,24 +64,25 @@ import java.util.stream.StreamSupport; import jdk.internal.jshell.debug.InternalDebugControl; import jdk.internal.jshell.tool.IOContext.InputInterruptedException; +import jdk.jshell.DeclarationSnippet; import jdk.jshell.Diag; import jdk.jshell.EvalException; +import jdk.jshell.ExpressionSnippet; +import jdk.jshell.ImportSnippet; import jdk.jshell.JShell; -import jdk.jshell.Snippet; -import jdk.jshell.DeclarationSnippet; -import jdk.jshell.TypeDeclSnippet; +import jdk.jshell.JShell.Subscription; import jdk.jshell.MethodSnippet; import jdk.jshell.PersistentSnippet; -import jdk.jshell.VarSnippet; -import jdk.jshell.ExpressionSnippet; +import jdk.jshell.Snippet; import jdk.jshell.Snippet.Status; +import jdk.jshell.Snippet.SubKind; +import jdk.jshell.SnippetEvent; import jdk.jshell.SourceCodeAnalysis; import jdk.jshell.SourceCodeAnalysis.CompletionInfo; import jdk.jshell.SourceCodeAnalysis.Suggestion; -import jdk.jshell.SnippetEvent; +import jdk.jshell.TypeDeclSnippet; import jdk.jshell.UnresolvedReferenceException; -import jdk.jshell.Snippet.SubKind; -import jdk.jshell.JShell.Subscription; +import jdk.jshell.VarSnippet; import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; @@ -94,7 +93,12 @@ import java.util.ResourceBundle; import java.util.Spliterators; import java.util.function.Function; import java.util.function.Supplier; +import jdk.internal.jshell.tool.Feedback.FormatAction; +import jdk.internal.jshell.tool.Feedback.FormatCase; +import jdk.internal.jshell.tool.Feedback.FormatResolve; +import jdk.internal.jshell.tool.Feedback.FormatWhen; import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; import static jdk.jshell.Snippet.SubKind.VAR_VALUE_SUBKIND; /** @@ -103,6 +107,7 @@ import static jdk.jshell.Snippet.SubKind.VAR_VALUE_SUBKIND; */ public class JShellTool { + private static final String LINE_SEP = System.getProperty("line.separator"); private static final Pattern LINEBREAK = Pattern.compile("\\R"); private static final Pattern HISTORY_ALL_START_FILENAME = Pattern.compile( "((?(all|history|start))(\\z|\\p{javaWhitespace}+))?(?.*)"); @@ -116,6 +121,8 @@ public class JShellTool { final PrintStream userout; final PrintStream usererr; + final Feedback feedback = new Feedback(); + /** * The constructor for the tool (used by tool launch via main and by test * harnesses to capture ins and outs. @@ -137,6 +144,70 @@ public class JShellTool { this.userin = userin; this.userout = userout; this.usererr = usererr; + initializeFeedbackModes(); + } + + /** + * Create the default set of feedback modes + */ + final void initializeFeedbackModes() { + // Initialize normal feedback mode + cmdSet("newmode normal command"); + cmdSet("prompt normal '\n-> ' '>> '"); + cmdSet("field normal pre '| '"); + cmdSet("field normal post '%n'"); + cmdSet("field normal errorpre '| '"); + cmdSet("field normal errorpost '%n'"); + cmdSet("field normal action 'Added' added-primary"); + cmdSet("field normal action 'Modified' modified-primary"); + cmdSet("field normal action 'Replaced' replaced-primary"); + cmdSet("field normal action 'Overwrote' overwrote-primary"); + cmdSet("field normal action 'Dropped' dropped-primary"); + cmdSet("field normal action 'Rejected' rejected-primary"); + cmdSet("field normal action ' Update added' added-update"); + cmdSet("field normal action ' Update modified' modified-update"); + cmdSet("field normal action ' Update replaced' replaced-update"); + cmdSet("field normal action ' Update overwrote' overwrote-update"); + cmdSet("field normal action ' Update dropped' dropped-update"); + cmdSet("field normal action ' Update rejected' rejected-update"); + cmdSet("field normal resolve '' ok-*"); + cmdSet("field normal resolve ', however, it cannot be invoked until%s is declared' defined-primary"); + cmdSet("field normal resolve ', however, it cannot be referenced until%s is declared' notdefined-primary"); + cmdSet("field normal resolve ' which cannot be invoked until%s is declared' defined-update"); + cmdSet("field normal resolve ' which cannot be referenced until%s is declared' notdefined-update"); + cmdSet("field normal name '%s'"); + cmdSet("field normal type '%s'"); + cmdSet("field normal result '%s'"); + + cmdSet("format normal '' *-*-*"); + + cmdSet("format normal '{pre}{action} class {name}{resolve}{post}' class"); + cmdSet("format normal '{pre}{action} interface {name}{resolve}{post}' interface"); + cmdSet("format normal '{pre}{action} enum {name}{resolve}{post}' enum"); + cmdSet("format normal '{pre}{action} annotation interface {name}{resolve}{post}' annotation"); + + cmdSet("format normal '{pre}{action} method {name}({type}){resolve}{post}' method"); + + cmdSet("format normal '{pre}{action} variable {name} of type {type}{resolve}{post}' vardecl"); + cmdSet("format normal '{pre}{action} variable {name} of type {type} with initial value {result}{resolve}{post}' varinit"); + cmdSet("format normal '{pre}{action} variable {name}{resolve}{post}' vardeclrecoverable"); + cmdSet("format normal '{pre}{action} variable {name}, reset to null{post}' varreset-*-update"); + + cmdSet("format normal '{pre}Expression value is: {result}{post}" + + "{pre} assigned to temporary variable {name} of type {type}{post}' expression"); + cmdSet("format normal '{pre}Variable {name} of type {type} has value {result}{post}' varvalue"); + cmdSet("format normal '{pre}Variable {name} has been assigned the value {result}{post}' assignment"); + + cmdSet("feedback normal"); + + // Initialize off feedback mode + cmdSet("newmode off quiet"); + cmdSet("prompt off '-> ' '>> '"); + cmdSet("field off pre '| '"); + cmdSet("field off post '%n'"); + cmdSet("field off errorpre '| '"); + cmdSet("field off errorpost '%n'"); + cmdSet("format off '' *-*-*"); } private IOContext input = null; @@ -150,7 +221,6 @@ public class JShellTool { private boolean debug = false; private boolean displayPrompt = true; public boolean testPrompt = false; - private Feedback feedback = Feedback.Default; private String cmdlineClasspath = null; private String cmdlineStartup = null; private String[] editor = null; @@ -185,6 +255,15 @@ public class JShellTool { Map mapSnippet; + /** + * Is the input/output currently interactive + * + * @return true if console + */ + boolean interactive() { + return input != null && input.interactiveOutput(); + } + void debug(String format, Object... args) { if (debug) { cmderr.printf(format + "\n", args); @@ -192,38 +271,98 @@ public class JShellTool { } /** - * For more verbose feedback modes - * @param format printf format - * @param args printf args + * Base output for command output -- no pre- or post-fix + * + * @param printf format + * @param printf args */ - void fluff(String format, Object... args) { - if (feedback() != Feedback.Off && feedback() != Feedback.Concise) { - hard(format, args); - } + void rawout(String format, Object... args) { + cmdout.printf(format, args); } /** - * For concise feedback mode only - * @param format printf format - * @param args printf args - */ - void concise(String format, Object... args) { - if (feedback() == Feedback.Concise) { - hard(format, args); - } - } - - /** - * For all feedback modes -- must show + * Must show command output + * * @param format printf format * @param args printf args */ void hard(String format, Object... args) { - cmdout.printf("| " + format + "\n", args); + rawout(feedback.getPre() + format + feedback.getPost(), args); + } + + /** + * Error command output + * + * @param format printf format + * @param args printf args + */ + void error(String format, Object... args) { + rawout(feedback.getErrorPre() + format + feedback.getErrorPost(), args); + } + + /** + * Optional output + * + * @param format printf format + * @param args printf args + */ + void fluff(String format, Object... args) { + if (feedback.shouldDisplayCommandFluff() && interactive()) { + hard(format, args); + } + } + + /** + * Optional output -- with embedded per- and post-fix + * + * @param format printf format + * @param args printf args + */ + void fluffRaw(String format, Object... args) { + if (feedback.shouldDisplayCommandFluff() && interactive()) { + rawout(format, args); + } + } + + void hardPairs(Stream stream, Function a, Function b) { + Map a2b = stream.collect(toMap(a, b, + (m1, m2) -> m1, + () -> new LinkedHashMap<>())); + int aLen = 0; + for (String av : a2b.keySet()) { + aLen = Math.max(aLen, av.length()); + } + String format = " %-" + aLen + "s -- %s"; + String indentedNewLine = LINE_SEP + feedback.getPre() + + String.format(" %-" + (aLen + 4) + "s", ""); + for (Entry e : a2b.entrySet()) { + hard(format, e.getKey(), e.getValue().replaceAll("\n", indentedNewLine)); + } + } + + /** + * User custom feedback mode only + * + * @param fcase Event to report + * @param update Is this an update (rather than primary) + * @param fa Action + * @param fr Resolution status + * @param name Name string + * @param type Type string or null + * @param result Result value or null + * @param unresolved The unresolved symbols + */ + void custom(FormatCase fcase, boolean update, FormatAction fa, FormatResolve fr, + String name, String type, String unresolved, String result) { + String format = feedback.getFormat(fcase, + (update ? FormatWhen.UPDATE : FormatWhen.PRIMARY), fa, fr, + name != null, type != null, result != null); + fluffRaw(format, unresolved, name, type, result); } /** * Trim whitespace off end of string + * * @param s * @return */ @@ -276,8 +415,8 @@ public class JShellTool { } if (regenerateOnDeath) { - fluff("Welcome to JShell -- Version %s", version()); - fluff("Type /help for help"); + hard("Welcome to JShell -- Version %s", version()); + hard("Type /help for help"); } try { @@ -369,14 +508,14 @@ public class JShellTool { } private void printUsage() { - cmdout.printf("Usage: jshell \n"); - cmdout.printf("where possible options include:\n"); - cmdout.printf(" -classpath Specify where to find user class files\n"); - cmdout.printf(" -cp Specify where to find user class files\n"); - cmdout.printf(" -startup One run replacement for the start-up definitions\n"); - cmdout.printf(" -nostartup Do not run the start-up definitions\n"); - cmdout.printf(" -help Print a synopsis of standard options\n"); - cmdout.printf(" -version Version information\n"); + rawout("Usage: jshell \n"); + rawout("where possible options include:\n"); + rawout(" -classpath Specify where to find user class files\n"); + rawout(" -cp Specify where to find user class files\n"); + rawout(" -startup One run replacement for the start-up definitions\n"); + rawout(" -nostartup Do not run the start-up definitions\n"); + rawout(" -help Print a synopsis of standard options\n"); + rawout(" -version Version information\n"); } private void resetState() { @@ -460,10 +599,8 @@ public class JShellTool { ? "\u0005" //ENQ : "\u0006" //ACK : incomplete.isEmpty() - ? feedback() == Feedback.Concise - ? "-> " - : "\n-> " - : ">> " + ? feedback.getPrompt(currentNameSpace.tidNext()) + : feedback.getContinuationPrompt(currentNameSpace.tidNext()) ; } else { prompt = ""; @@ -541,7 +678,7 @@ public class JShellTool { Command[] candidates = findCommand(cmd, c -> c.kind.isRealCommand); if (candidates.length == 0) { if (!rerunHistoryEntryById(cmd.substring(1))) { - hard("No such command or snippet id: %s", cmd); + error("No such command or snippet id: %s", cmd); fluff("Type /help for help."); } } else if (candidates.length == 1) { @@ -552,7 +689,7 @@ public class JShellTool { addToReplayHistory((command.command + " " + arg).trim()); } } else { - hard("Command: %s is ambiguous: %s", cmd, Arrays.stream(candidates).map(c -> c.command).collect(Collectors.joining(", "))); + error("Command: %s is ambiguous: %s", cmd, Arrays.stream(candidates).map(c -> c.command).collect(Collectors.joining(", "))); fluff("Type /help for help."); } } @@ -635,45 +772,6 @@ public class JShellTool { } } - class ArgTokenizer extends StreamTokenizer { - - ArgTokenizer(String arg) { - super(new StringReader(arg)); - resetSyntax(); - wordChars(0x00, 0xFF); - quoteChar('"'); - quoteChar('\''); - - whitespaceChars(0x09, 0x0D); - whitespaceChars(0x1C, 0x20); - whitespaceChars(0x85, 0x85); - whitespaceChars(0xA0, 0xA0); - whitespaceChars(0x1680, 0x1680); - whitespaceChars(0x180E, 0x180E); - whitespaceChars(0x2000, 0x200A); - whitespaceChars(0x202F, 0x202F); - whitespaceChars(0x205F, 0x205F); - whitespaceChars(0x3000, 0x3000); - } - - String next() { - try { - nextToken(); - } catch (Throwable t) { - return null; - } - return sval; - } - - String val() { - return sval; - } - - boolean isQuoted() { - return ttype == '\'' || ttype == '"'; - } - } - static final class FixedCompletionProvider implements CompletionProvider { private final String[] alternatives; @@ -801,16 +899,9 @@ public class JShellTool { " -- List the snippet with the specified snippet id\n", arg -> cmdList(arg), editKeywordCompletion())); - registerCommand(new Command("/seteditor", "", "set the external editor command to use", - "Specify the command to launch for the /edit command.\n" + - "The command is an operating system dependent string.\n" + - "The command may include space-separated arguments (such as flags).\n" + - "When /edit is used, temporary file to edit will be appended as the last argument.\n", - arg -> cmdSetEditor(arg), - EMPTY_COMPLETION_PROVIDER)); registerCommand(new Command("/edit", "", "edit a source entry referenced by name or id", "Edit a snippet or snippets of source in an external editor.\n" + - "The editor to use is set with /seteditor.\n" + + "The editor to use is set with /set editor.\n" + "If no editor has been set, a simple editor will be launched.\n\n" + "/edit \n" + " -- Edit the snippet or snippets with the specified name (preference for active snippets)\n" + @@ -875,7 +966,7 @@ public class JShellTool { " * Start-up code is re-executed.\n" + " * The execution state is restarted.\n" + " * The classpath is cleared.\n" + - "Tool settings are maintained: /feedback, /prompt, and /seteditor\n" + + "Tool settings are maintained, as set with: /set ...\n" + "Save any work before using this command\n", arg -> cmdReset(), EMPTY_COMPLETION_PROVIDER)); @@ -895,25 +986,6 @@ public class JShellTool { " -- With the 'quiet' argument the replay is not shown. Errors will display.\n", arg -> cmdReload(arg), reloadCompletion())); - registerCommand(new Command("/feedback", "", "feedback information: off, concise, normal, verbose, default, or ?", - "Set the level of feedback describing the effect of commands and snippets.\n\n" + - "/feedback off\n" + - " -- Give no feedback\n" + - "/feedback concise\n" + - " -- Brief and generally symbolic feedback\n" + - "/feedback normal\n" + - " -- Give a natural language description of the actions\n" + - "/feedback verbose\n" + - " -- Like normal but with side-effects described\n" + - "/feedback default\n" + - " -- Same as normal for user input, off for input from a file\n", - arg -> cmdFeedback(arg), - new FixedCompletionProvider("off", "concise", "normal", "verbose", "default", "?"))); - registerCommand(new Command("/prompt", null, "toggle display of a prompt", - "Toggle between displaying an input prompt and not displaying a prompt.\n" + - "Particularly useful when pasting large amounts of text.\n", - arg -> cmdPrompt(), - EMPTY_COMPLETION_PROVIDER)); registerCommand(new Command("/classpath", "", "add a path to the classpath", "Append a additional path to the classpath.\n", arg -> cmdClasspath(arg), @@ -923,10 +995,6 @@ public class JShellTool { "Display the history of snippet and command input since this jshell was launched.\n", arg -> cmdHistory(), EMPTY_COMPLETION_PROVIDER)); - registerCommand(new Command("/setstart", "", "read file and set as the new start-up definitions", - "The contents of the specified file become the default start-up snippets and commands.\n", - arg -> cmdSetStart(arg), - FILE_COMPLETION_PROVIDER)); registerCommand(new Command("/debug", null, "toggle debugging of the jshell", "Display debugging information for the jshelll implementation.\n" + "0: Debugging off\n" + @@ -951,6 +1019,37 @@ public class JShellTool { " -- Display information about the specified help subject. Example: /help intro\n", arg -> cmdHelp(arg), EMPTY_COMPLETION_PROVIDER)); + registerCommand(new Command("/set", "editor|start|feedback|newmode|prompt|format|field ...", "set jshell configuration information", + "Set jshell configuration information, including:\n" + + "the external editor to use, the start-up definitions to use, a new feedback mode,\n" + + "the command prompt, the feedback mode to use, or the format of output.\n" + + "\n" + + "/set editor ...\n" + + " -- Specify the command to launch for the /edit command.\n" + + " The is an operating system dependent string.\n" + + "\n" + + "/set start \n" + + " -- The contents of the specified become the default start-up snippets and commands.\n" + + "\n" + + "/set feedback \n" + + " -- Set the feedback mode describing displayed feedback for entered snippets and commands.\n" + + "\n" + + "/set newmode [command|quiet []]\n" + + " -- Create a user-defined feedback mode, optionally copying from an existing mode.\n" + + "\n" + + "/set prompt \"\" \"\"\n" + + " -- Set the displayed prompts for a given feedback mode.\n" + + "\n" + + "/set format \"\" ...\n" + + " -- Configure a feedback mode by setting the format to use in a specified set of cases.\n" + + "\n" + + "/set field name|type|result|when|action|resolve|pre|post|errorpre|errorpost \"\" ...\n" + + " -- Set the format of a field within the of a \"/set format\" command\n" + + "\n" + + "To get more information about one of these forms, use /help with the form specified.\n" + + "For example: /help /set format\n", + arg -> cmdSet(arg), + new FixedCompletionProvider("format", "field", "feedback", "prompt", "newmode", "start", "editor"))); registerCommand(new Command("/?", "", "get information about jshell", "Display information about jshell (abbreviation for /help).\n" + "/?\n" + @@ -1051,19 +1150,136 @@ public class JShellTool { // --- Command implementations --- - boolean cmdSetEditor(String arg) { - if (arg.isEmpty()) { - hard("/seteditor requires a path argument"); + private static final String[] setSub = new String[]{ + "format", "field", "feedback", "newmode", "prompt", "editor", "start"}; + + // The /set command. Currently /set format, /set field and /set feedback. + // Other commands will fold here, see: 8148317 + final boolean cmdSet(String arg) { + ArgTokenizer at = new ArgTokenizer(arg.trim()); + String which = setSubCommand(at); + if (which == null) { return false; - } else { - List ed = new ArrayList<>(); - ArgTokenizer at = new ArgTokenizer(arg); - String n; - while ((n = at.next()) != null) ed.add(n); - editor = ed.toArray(new String[ed.size()]); - fluff("Editor set to: %s", arg); - return true; } + switch (which) { + case "format": + return feedback.setFormat(this, at); + case "field": + return feedback.setField(this, at); + case "feedback": + return feedback.setFeedback(this, at); + case "newmode": + return feedback.setNewMode(this, at); + case "prompt": + return feedback.setPrompt(this, at); + case "editor": { + String prog = at.next(); + if (prog == null) { + hard("The '/set editor' command requires a path argument"); + return false; + } else { + List ed = new ArrayList<>(); + ed.add(prog); + String n; + while ((n = at.next()) != null) { + ed.add(n); + } + editor = ed.toArray(new String[ed.size()]); + fluff("Editor set to: %s", arg); + return true; + } + } + case "start": { + String filename = at.next(); + if (filename == null) { + hard("The '/set start' command requires a filename argument."); + } else { + try { + byte[] encoded = Files.readAllBytes(toPathResolvingUserHome(filename)); + String init = new String(encoded); + PREFS.put(STARTUP_KEY, init); + } catch (AccessDeniedException e) { + hard("File '%s' for /set start is not accessible.", filename); + return false; + } catch (NoSuchFileException e) { + hard("File '%s' for /set start is not found.", filename); + return false; + } catch (Exception e) { + hard("Exception while reading start set file: %s", e); + return false; + } + } + return true; + } + default: + hard("Error: Invalid /set argument: %s", which); + return false; + } + } + + boolean printSetHelp(ArgTokenizer at) { + String which = setSubCommand(at); + if (which == null) { + return false; + } + switch (which) { + case "format": + feedback.printFormatHelp(this); + return true; + case "field": + feedback.printFieldHelp(this); + return true; + case "feedback": + feedback.printFeedbackHelp(this); + return true; + case "newmode": + feedback.printNewModeHelp(this); + return true; + case "prompt": + feedback.printPromptHelp(this); + return true; + case "editor": + hard("Specify the command to launch for the /edit command."); + hard(""); + hard("/set editor ..."); + hard(""); + hard("The is an operating system dependent string."); + hard("The may include space-separated arguments (such as flags) -- ...."); + hard("When /edit is used, the temporary file to edit will be appended as the last argument."); + return true; + case "start": + hard("Set the start-up configuration -- a sequence of snippets and commands read at start-up."); + hard(""); + hard("/set start "); + hard(""); + hard("The contents of the specified become the default start-up snippets and commands --"); + hard("which are run when the jshell tool is started or reset."); + return true; + default: + hard("Error: Invalid /set argument: %s", which); + return false; + } + } + + String setSubCommand(ArgTokenizer at) { + String[] matches = at.next(setSub); + if (matches == null) { + error("The /set command requires arguments. See: /help /set"); + return null; + } else if (matches.length == 0) { + error("Not a valid argument to /set: %s", at.val()); + fluff("/set is followed by one of: %s", Arrays.stream(setSub) + .collect(Collectors.joining(", ")) + ); + return null; + } else if (matches.length > 1) { + error("Ambiguous argument to /set: %s", at.val()); + fluff("Use one of: %s", Arrays.stream(matches) + .collect(Collectors.joining(", ")) + ); + return null; + } + return matches[0]; } boolean cmdClasspath(String arg) { @@ -1137,91 +1353,50 @@ public class JShellTool { return true; } - private boolean cmdFeedback(String arg) { - switch (arg) { - case "": - case "d": - case "default": - feedback = Feedback.Default; - break; - case "o": - case "off": - feedback = Feedback.Off; - break; - case "c": - case "concise": - feedback = Feedback.Concise; - break; - case "n": - case "normal": - feedback = Feedback.Normal; - break; - case "v": - case "verbose": - feedback = Feedback.Verbose; - break; - default: - hard("Follow /feedback with of the following:"); - hard(" off (errors and critical output only)"); - hard(" concise"); - hard(" normal"); - hard(" verbose"); - hard(" default"); - hard("You may also use just the first letter, for example: /f c"); - hard("In interactive mode 'default' is the same as 'normal', from a file it is the same as 'off'"); - return false; - } - fluff("Feedback mode: %s", feedback.name().toLowerCase()); - return true; - } - boolean cmdHelp(String arg) { - if (!arg.isEmpty()) { - StringBuilder sb = new StringBuilder(); - commands.values().stream() - .filter(c -> c.command.startsWith(arg)) - .forEach(c -> { - sb.append("\n"); - sb.append(c.command); - sb.append("\n\n"); - sb.append(c.help); - sb.append("\n"); - }); - if (sb.length() > 0) { - cmdout.print(sb); - return true; + ArgTokenizer at = new ArgTokenizer(arg); + String subject = at.next(); + if (subject != null) { + Command[] matches = commands.values().stream() + .filter(c -> c.command.startsWith(subject)) + .toArray(size -> new Command[size]); + at.mark(); + String sub = at.next(); + if (sub != null && matches.length == 1 && matches[0].command.equals("/set")) { + at.rewind(); + return printSetHelp(at); + } + if (matches.length > 0) { + for (Command c : matches) { + hard(""); + hard("%s", c.command); + hard(""); + hard("%s", c.help.replaceAll("\n", LINE_SEP + feedback.getPre())); + } + return true; + } else { + error("No commands or subjects start with the provided argument: %s\n\n", arg); } - cmdout.printf("No commands or subjects start with the provided argument: %s\n\n", arg); } - int synopsisLen = 0; - Map synopsis2Description = new LinkedHashMap<>(); - for (Command cmd : new LinkedHashSet<>(commands.values())) { - if (!cmd.kind.showInHelp) - continue; - StringBuilder synopsis = new StringBuilder(); - synopsis.append(cmd.command); - if (cmd.params != null) - synopsis.append(" ").append(cmd.params); - synopsis2Description.put(synopsis.toString(), cmd.description); - synopsisLen = Math.max(synopsisLen, synopsis.length()); - } - cmdout.println("Type a Java language expression, statement, or declaration."); - cmdout.println("Or type one of the following commands:\n"); - for (Entry e : synopsis2Description.entrySet()) { - cmdout.print(String.format("%-" + synopsisLen + "s", e.getKey())); - cmdout.print(" -- "); - String indentedNewLine = System.getProperty("line.separator") + - String.format("%-" + (synopsisLen + 4) + "s", ""); - cmdout.println(e.getValue().replace("\n", indentedNewLine)); - } - cmdout.println(); - cmdout.println("For more information type '/help' followed by the name of command or a subject."); - cmdout.println("For example '/help /list' or '/help intro'. Subjects:\n"); - commands.values().stream() - .filter(c -> c.kind == CommandKind.HELP_SUBJECT) - .forEach(c -> { - cmdout.printf("%-12s -- %s\n", c.command, c.description); - }); + hard("Type a Java language expression, statement, or declaration."); + hard("Or type one of the following commands:"); + hard(""); + hardPairs(commands.values().stream() + .filter(cmd -> cmd.kind.showInHelp), + cmd -> (cmd.params != null) + ? cmd.command + " " + cmd.params + : cmd.command, + cmd -> cmd.description + ); + hard(""); + hard("For more information type '/help' followed by the name of command or a subject."); + hard("For example '/help /list' or '/help intro'. Subjects:"); + hard(""); + hardPairs(commands.values().stream() + .filter(cmd -> cmd.kind == CommandKind.HELP_SUBJECT), + cmd -> cmd.command, + cmd -> cmd.description + ); return true; } @@ -1482,13 +1657,6 @@ public class JShellTool { return true; } - private boolean cmdPrompt() { - displayPrompt = !displayPrompt; - fluff("Prompt will %sdisplay. Use /prompt to toggle.", displayPrompt ? "" : "NOT "); - concise("Prompt: %s", displayPrompt ? "on" : "off"); - return true; - } - private boolean cmdReset() { live = false; fluff("Resetting state."); @@ -1577,28 +1745,6 @@ public class JShellTool { return true; } - private boolean cmdSetStart(String filename) { - if (filename.isEmpty()) { - hard("The /setstart command requires a filename argument."); - } else { - try { - byte[] encoded = Files.readAllBytes(toPathResolvingUserHome(filename)); - String init = new String(encoded); - PREFS.put(STARTUP_KEY, init); - } catch (AccessDeniedException e) { - hard("File '%s' for /setstart is not accessible.", filename); - return false; - } catch (NoSuchFileException e) { - hard("File '%s' for /setstart is not found.", filename); - return false; - } catch (Exception e) { - hard("Exception while reading start set file: %s", e); - return false; - } - } - return true; - } - private boolean cmdVars() { for (VarSnippet vk : state.variables()) { String val = state.status(vk) == Status.VALID @@ -1831,14 +1977,10 @@ public class JShellTool { printDiagnostics(source, diagnostics, true); } else { // Update - SubKind subkind = sn.subKind(); - if (sn instanceof DeclarationSnippet - && (feedback() == Feedback.Verbose - || ste.status() == Status.OVERWRITTEN - || subkind == SubKind.VAR_DECLARATION_SUBKIND - || subkind == SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND)) { - // Under the conditions, display update information - displayDeclarationAndValue(ste, true, null); + if (sn instanceof DeclarationSnippet) { + // display update information + displayDeclarationAndValue(ste, true, ste.value()); + List other = errorsOnly(diagnostics); if (other.size() > 0) { printDiagnostics(source, other, true); @@ -1851,118 +1993,117 @@ public class JShellTool { @SuppressWarnings("fallthrough") private void displayDeclarationAndValue(SnippetEvent ste, boolean update, String value) { Snippet key = ste.snippet(); - String declared; + FormatAction action; Status status = ste.status(); switch (status) { case VALID: case RECOVERABLE_DEFINED: case RECOVERABLE_NOT_DEFINED: if (ste.previousStatus().isActive) { - declared = ste.isSignatureChange() - ? "Replaced" - : "Modified"; + action = ste.isSignatureChange() + ? FormatAction.REPLACED + : FormatAction.MODIFIED; } else { - declared = "Added"; + action = FormatAction.ADDED; } break; case OVERWRITTEN: - declared = "Overwrote"; + action = FormatAction.OVERWROTE; break; case DROPPED: - declared = "Dropped"; + action = FormatAction.DROPPED; break; case REJECTED: - declared = "Rejected"; + action = FormatAction.REJECTED; break; case NONEXISTENT: default: // Should not occur - declared = ste.previousStatus().toString() + "=>" + status.toString(); + error("Unexpected status: " + ste.previousStatus().toString() + "=>" + status.toString()); + return; } - if (update) { - declared = " Update " + declared.toLowerCase(); - } - String however; + FormatResolve resolution; + String unresolved; if (key instanceof DeclarationSnippet && (status == Status.RECOVERABLE_DEFINED || status == Status.RECOVERABLE_NOT_DEFINED)) { - String cannotUntil = (status == Status.RECOVERABLE_NOT_DEFINED) - ? " cannot be referenced until" - : " cannot be invoked until"; - however = (update? " which" : ", however, it") + cannotUntil + unresolved((DeclarationSnippet) key); + resolution = (status == Status.RECOVERABLE_NOT_DEFINED) + ? FormatResolve.NOTDEFINED + : FormatResolve.DEFINED; + unresolved = unresolved((DeclarationSnippet) key); } else { - however = ""; + resolution = FormatResolve.OK; + unresolved = ""; } switch (key.subKind()) { case CLASS_SUBKIND: - fluff("%s class %s%s", declared, ((TypeDeclSnippet) key).name(), however); + custom(FormatCase.CLASS, update, action, resolution, + ((TypeDeclSnippet) key).name(), null, unresolved, null); break; case INTERFACE_SUBKIND: - fluff("%s interface %s%s", declared, ((TypeDeclSnippet) key).name(), however); + custom(FormatCase.INTERFACE, update, action, resolution, + ((TypeDeclSnippet) key).name(), null, unresolved, null); break; case ENUM_SUBKIND: - fluff("%s enum %s%s", declared, ((TypeDeclSnippet) key).name(), however); + custom(FormatCase.ENUM, update, action, resolution, + ((TypeDeclSnippet) key).name(), null, unresolved, null); break; case ANNOTATION_TYPE_SUBKIND: - fluff("%s annotation interface %s%s", declared, ((TypeDeclSnippet) key).name(), however); + custom(FormatCase.ANNOTATION, update, action, resolution, + ((TypeDeclSnippet) key).name(), null, unresolved, null); break; case METHOD_SUBKIND: - fluff("%s method %s(%s)%s", declared, ((MethodSnippet) key).name(), - ((MethodSnippet) key).parameterTypes(), however); + custom(FormatCase.METHOD, update, action, resolution, + ((MethodSnippet) key).name(), ((MethodSnippet) key).parameterTypes(), unresolved, null); break; case VAR_DECLARATION_SUBKIND: - if (!update) { - VarSnippet vk = (VarSnippet) key; - if (status == Status.RECOVERABLE_NOT_DEFINED) { - fluff("%s variable %s%s", declared, vk.name(), however); - } else { - fluff("%s variable %s of type %s%s", declared, vk.name(), vk.typeName(), however); - } - break; - } - // Fall through case VAR_DECLARATION_WITH_INITIALIZER_SUBKIND: { VarSnippet vk = (VarSnippet) key; if (status == Status.RECOVERABLE_NOT_DEFINED) { - if (!update) { - fluff("%s variable %s%s", declared, vk.name(), however); - break; - } - } else if (update) { - if (ste.isSignatureChange()) { - hard("%s variable %s, reset to null", declared, vk.name()); - } + custom(FormatCase.VARDECLRECOVERABLE, update, action, resolution, + vk.name(), null, unresolved, null); + } else if (update && ste.isSignatureChange()) { + custom(FormatCase.VARRESET, update, action, resolution, + vk.name(), null, unresolved, value); + } else if (key.subKind() == SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND) { + custom(FormatCase.VARINIT, update, action, resolution, + vk.name(), vk.typeName(), unresolved, value); } else { - fluff("%s variable %s of type %s with initial value %s", - declared, vk.name(), vk.typeName(), value); - concise("%s : %s", vk.name(), value); + custom(FormatCase.VARDECL, update, action, resolution, + vk.name(), vk.typeName(), unresolved, value); } break; } case TEMP_VAR_EXPRESSION_SUBKIND: { VarSnippet vk = (VarSnippet) key; - if (update) { - hard("%s temporary variable %s, reset to null", declared, vk.name()); - } else { - fluff("Expression value is: %s", (value)); - fluff(" assigned to temporary variable %s of type %s", vk.name(), vk.typeName()); - concise("%s : %s", vk.name(), value); - } + custom(FormatCase.EXPRESSION, update, action, resolution, + vk.name(), vk.typeName(), null, value); break; } case OTHER_EXPRESSION_SUBKIND: - fluff("Expression value is: %s", (value)); + error("Unexpected expression form -- value is: %s", (value)); break; case VAR_VALUE_SUBKIND: { ExpressionSnippet ek = (ExpressionSnippet) key; - fluff("Variable %s of type %s has value %s", ek.name(), ek.typeName(), (value)); - concise("%s : %s", ek.name(), value); + custom(FormatCase.VARVALUE, update, action, resolution, + ek.name(), ek.typeName(), null, value); break; } case ASSIGNMENT_SUBKIND: { ExpressionSnippet ek = (ExpressionSnippet) key; - fluff("Variable %s has been assigned the value %s", ek.name(), (value)); - concise("%s : %s", ek.name(), value); + custom(FormatCase.ASSIGNMENT, update, action, resolution, + ek.name(), ek.typeName(), null, value); break; } + case SINGLE_TYPE_IMPORT_SUBKIND: + case TYPE_IMPORT_ON_DEMAND_SUBKIND: + case SINGLE_STATIC_IMPORT_SUBKIND: + case STATIC_IMPORT_ON_DEMAND_SUBKIND: + custom(FormatCase.IMPORT, update, action, resolution, + ((ImportSnippet) key).name(), null, null, null); + break; + case STATEMENT_SUBKIND: + custom(FormatCase.STATEMENT, update, action, resolution, + null, null, null, null); + break; } } //where @@ -2048,34 +2189,9 @@ public class JShellTool { sb.append(", "); } } - switch (unr.size()) { - case 0: - break; - case 1: - sb.append(" is declared"); - break; - default: - sb.append(" are declared"); - break; - } return sb.toString(); } - enum Feedback { - Default, - Off, - Concise, - Normal, - Verbose - } - - Feedback feedback() { - if (feedback == Feedback.Default) { - return input == null || input.interactiveOutput() ? Feedback.Normal : Feedback.Off; - } - return feedback; - } - /** The current version number as a string. */ static String version() { diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java index 462d61e87de..2ae696a026f 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -231,7 +231,7 @@ class CompletenessAnalyzer { // Declarations and type parameters (thus expressions) EXTENDS(TokenKind.EXTENDS, XEXPR|XDECL), // extends - COMMA(TokenKind.COMMA, XEXPR|XDECL|XSTART), // , + COMMA(TokenKind.COMMA, XEXPR|XDECL), // , AMP(TokenKind.AMP, XEXPR|XDECL), // & GT(TokenKind.GT, XEXPR|XDECL), // > LT(TokenKind.LT, XEXPR|XDECL1), // < diff --git a/langtools/test/jdk/jshell/CommandCompletionTest.java b/langtools/test/jdk/jshell/CommandCompletionTest.java index 1ca831f0c13..07f7fc3e397 100644 --- a/langtools/test/jdk/jshell/CommandCompletionTest.java +++ b/langtools/test/jdk/jshell/CommandCompletionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -50,13 +50,9 @@ import org.testng.annotations.Test; public class CommandCompletionTest extends ReplToolTesting { public void testCommand() { - assertCompletion("/f|", false, "/feedback "); assertCompletion("/deb|", false); - assertCompletion("/feedback v|", false, "verbose"); assertCompletion("/c|", false, "/classes ", "/classpath "); assertCompletion("/h|", false, "/help ", "/history "); - assertCompletion("/feedback |", false, - "?", "concise", "default", "normal", "off", "verbose"); } public void testList() { @@ -108,7 +104,7 @@ public class CommandCompletionTest extends ReplToolTesting { public void testSave() throws IOException { Compiler compiler = new Compiler(); - assertCompletion("/s|", false, "/save ", "/seteditor ", "/setstart "); + assertCompletion("/s|", false, "/save ", "/set "); List p1 = listFiles(Paths.get("")); Collections.addAll(p1, "all ", "history ", "start "); FileSystems.getDefault().getRootDirectories().forEach(s -> p1.add(s.toString())); diff --git a/langtools/test/jdk/jshell/CompletenessTest.java b/langtools/test/jdk/jshell/CompletenessTest.java index 893baeee6ed..bbf10d2b28b 100644 --- a/langtools/test/jdk/jshell/CompletenessTest.java +++ b/langtools/test/jdk/jshell/CompletenessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ /* * @test + * @bug 8149524 * @summary Test SourceCodeAnalysis * @build KullaTesting TestingInputStream * @run testng CompletenessTest @@ -60,6 +61,7 @@ public class CompletenessTest extends KullaTesting { "try { } finally { }", "try (java.util.zip.ZipFile zf = new java.util.zip.ZipFile(zipFileName)) { }", "foo: while (true) { printf(\"Innn\"); break foo; }", + "class Case, E2 extends Enum, E3 extends Enum> {}", ";", }; diff --git a/langtools/test/jdk/jshell/ExternalEditorTest.java b/langtools/test/jdk/jshell/ExternalEditorTest.java index b337c3d6d27..a794c7e57af 100644 --- a/langtools/test/jdk/jshell/ExternalEditorTest.java +++ b/langtools/test/jdk/jshell/ExternalEditorTest.java @@ -113,7 +113,7 @@ public class ExternalEditorTest extends EditorTestBase { @Override public void testEditor(boolean defaultStartup, String[] args, ReplTest... tests) { ReplTest[] t = new ReplTest[tests.length + 1]; - t[0] = a -> assertCommandCheckOutput(a, "/seteditor " + executionScript, + t[0] = a -> assertCommandCheckOutput(a, "/set editor " + executionScript, assertStartsWith("| Editor set to: " + executionScript)); System.arraycopy(tests, 0, t, 1, tests.length); super.testEditor(defaultStartup, args, t); @@ -193,8 +193,8 @@ public class ExternalEditorTest extends EditorTestBase { @Test public void setUnknownEditor() { test( - a -> assertCommand(a, "/seteditor", "| /seteditor requires a path argument\n"), - a -> assertCommand(a, "/seteditor UNKNOWN", "| Editor set to: UNKNOWN\n"), + a -> assertCommand(a, "/set editor", "| /set editor requires a path argument\n"), + a -> assertCommand(a, "/set editor UNKNOWN", "| Editor set to: UNKNOWN\n"), a -> assertCommand(a, "int a;", null), a -> assertCommand(a, "/e 1", "| Edit Error: process IO failure: Cannot run program \"UNKNOWN\": error=2, No such file or directory\n") @@ -204,7 +204,7 @@ public class ExternalEditorTest extends EditorTestBase { @Test(enabled = false) public void testRemoveTempFile() { test(new String[]{"-nostartup"}, - a -> assertCommandCheckOutput(a, "/seteditor " + executionScript, + a -> assertCommandCheckOutput(a, "/set editor " + executionScript, assertStartsWith("| Editor set to: " + executionScript)), a -> assertVariable(a, "int", "a", "0", "0"), a -> assertEditOutput(a, "/e 1", assertStartsWith("| Edit Error: Failure read edit file:"), () -> { diff --git a/langtools/test/jdk/jshell/ReplToolTesting.java b/langtools/test/jdk/jshell/ReplToolTesting.java index 05dd5389e0b..d4f697d3613 100644 --- a/langtools/test/jdk/jshell/ReplToolTesting.java +++ b/langtools/test/jdk/jshell/ReplToolTesting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -397,6 +397,15 @@ public class ReplToolTesting { assertCommand(after, cmd, out, "", null, "", ""); } + public void assertCommandOutputContains(boolean after, String cmd, String has) { + assertCommandCheckOutput(after, cmd, (s) -> + assertTrue(s.contains(has), "Output: \'" + s + "' does not contain: " + has)); + } + + public void assertCommandOutputStartsWith(boolean after, String cmd, String starts) { + assertCommandCheckOutput(after, cmd, assertStartsWith(starts)); + } + public void assertCommandCheckOutput(boolean after, String cmd, Consumer check) { if (!after) { assertCommand(false, cmd, null); @@ -437,13 +446,13 @@ public class ReplToolTesting { } private List computeCompletions(String code, boolean isSmart) { - JShellTool repl = this.repl != null ? this.repl + JShellTool js = this.repl != null ? this.repl : new JShellTool(null, null, null, null, null, null, null); int cursor = code.indexOf('|'); code = code.replace("|", ""); assertTrue(cursor > -1, "'|' not found: " + code); List completions = - repl.commandCompletionSuggestions(code, cursor, new int[1]); //XXX: ignoring anchor for now + js.commandCompletionSuggestions(code, cursor, new int[1]); //XXX: ignoring anchor for now return completions.stream() .filter(s -> isSmart == s.isSmart) .map(s -> s.continuation) @@ -481,6 +490,15 @@ public class ReplToolTesting { return name.hashCode(); } + @Override + public boolean equals(Object o) { + if (o instanceof MemberInfo) { + MemberInfo mi = (MemberInfo) o; + return name.equals(mi.name); + } + return false; + } + public abstract Consumer checkOutput(); public String getSource() { @@ -536,6 +554,11 @@ public class ReplToolTesting { "Output: " + output + " does not fit pattern: " + finalPattern); } + @Override + public int hashCode() { + return name.hashCode(); + } + @Override public boolean equals(Object o) { if (o instanceof VariableInfo) { @@ -585,6 +608,10 @@ public class ReplToolTesting { return s -> assertTrue(checkOutput.test(s), "Expected: '" + expectedOutput + "', actual: " + s); } + @Override + public int hashCode() { + return (name.hashCode() << 2) ^ type.hashCode() ; + } @Override public boolean equals(Object o) { @@ -615,6 +642,11 @@ public class ReplToolTesting { return s -> assertTrue(checkOutput.test(s), "Expected: '" + expectedOutput + "', actual: " + s); } + @Override + public int hashCode() { + return name.hashCode() ; + } + @Override public boolean equals(Object o) { if (o instanceof ClassInfo) { @@ -640,6 +672,11 @@ public class ReplToolTesting { return s -> assertTrue("".equals(s), "Expected: '', actual: " + s); } + @Override + public int hashCode() { + return (name.hashCode() << 2) ^ type.hashCode() ; + } + @Override public boolean equals(Object o) { if (o instanceof ImportInfo) { diff --git a/langtools/test/jdk/jshell/ToolBasicTest.java b/langtools/test/jdk/jshell/ToolBasicTest.java index f4501c84d32..e38ff644e77 100644 --- a/langtools/test/jdk/jshell/ToolBasicTest.java +++ b/langtools/test/jdk/jshell/ToolBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 + * @bug 8143037 8142447 8144095 8140265 8144906 8146138 8147887 8147886 8148316 8148317 * @requires os.family != "solaris" * @summary Tests for Basic tests for REPL tool * @library /tools/lib @@ -90,8 +90,7 @@ public class ToolBasicTest extends ReplToolTesting { public void elideStartUpFromList() { test( - (a) -> assertCommandCheckOutput(a, "123", (s) -> - assertTrue(s.contains("type int"), s)), + (a) -> assertCommandOutputContains(a, "123", "type int"), (a) -> assertCommandCheckOutput(a, "/list", (s) -> { int cnt; try (Scanner scanner = new Scanner(s)) { @@ -112,8 +111,7 @@ public class ToolBasicTest extends ReplToolTesting { Compiler compiler = new Compiler(); Path path = compiler.getPath("myfile"); test( - (a) -> assertCommandCheckOutput(a, "123", - (s) -> assertTrue(s.contains("type int"), s)), + (a) -> assertCommandOutputContains(a, "123", "type int"), (a) -> assertCommand(a, "/save " + path.toString(), "") ); try (Stream lines = Files.lines(path)) { @@ -594,12 +592,12 @@ public class ToolBasicTest extends ReplToolTesting { (a) -> assertMethod(a, "void f() {}", "()V", "f"), (a) -> assertImport(a, "import java.util.stream.*;", "", "java.util.stream.*"), (a) -> assertCommand(a, "/save " + startUpFile.toString(), null), - (a) -> assertCommand(a, "/setstart " + startUpFile.toString(), null) + (a) -> assertCommand(a, "/set start " + startUpFile.toString(), null) ); Path unknown = compiler.getPath("UNKNOWN"); test( - (a) -> assertCommand(a, "/setstart " + unknown.toString(), - "| File '" + unknown + "' for /setstart is not found.\n") + (a) -> assertCommand(a, "/set start " + unknown.toString(), + "| File '" + unknown + "' for /set start is not found.\n") ); test(false, new String[0], (a) -> { @@ -619,7 +617,7 @@ public class ToolBasicTest extends ReplToolTesting { } private void removeStartup() { - Preferences preferences = Preferences.userRoot().node("tool/REPL"); + Preferences preferences = Preferences.userRoot().node("tool/JShell"); if (preferences != null) { preferences.remove("STARTUP"); } @@ -636,7 +634,7 @@ public class ToolBasicTest extends ReplToolTesting { } public void testNoArgument() { - String[] commands = {"/save", "/open", "/setstart"}; + String[] commands = {"/save", "/open", "/set start"}; test(Stream.of(commands) .map(cmd -> { String c = cmd; @@ -670,8 +668,7 @@ public class ToolBasicTest extends ReplToolTesting { test( a -> assertVariable(a, "int", "x"), a -> assertCommandCheckOutput(a, "/vars", assertVariables()), - a -> assertCommandCheckOutput(a, "System.exit(5);", s -> - assertTrue(s.contains("terminated"), s)), + a -> assertCommandOutputContains(a, "System.exit(5);", "terminated"), a -> assertCommandCheckOutput(a, "/vars", s -> assertTrue(s.trim().isEmpty(), s)), a -> assertMethod(a, "void f() { }", "()void", "f"), @@ -699,8 +696,7 @@ public class ToolBasicTest extends ReplToolTesting { s -> assertEquals(s, "| No definition or id named " + arg + " found. There are no active definitions.\n")), a -> assertVariable(a, "int", "aardvark"), - a -> assertCommandCheckOutput(a, "/list aardvark", - s -> assertTrue(s.contains("aardvark"))), + a -> assertCommandOutputContains(a, "/list aardvark", "aardvark"), a -> assertCommandCheckOutput(a, "/list start", s -> checkLineToList(s, START_UP)), a -> assertCommandCheckOutput(a, "/list all", @@ -714,14 +710,14 @@ public class ToolBasicTest extends ReplToolTesting { } public void testFeedbackNegative() { - test(a -> assertCommandCheckOutput(a, "/feedback aaaa", - assertStartsWith("| Follow /feedback with of the following"))); + test(a -> assertCommandCheckOutput(a, "/set feedback aaaa", + assertStartsWith("| Does not match any current feedback mode"))); } public void testFeedbackOff() { for (String off : new String[]{"o", "off"}) { test( - a -> assertCommand(a, "/feedback " + off, ""), + a -> assertCommand(a, "/set feedback " + off, ""), a -> assertCommand(a, "int a", ""), a -> assertCommand(a, "void f() {}", ""), a -> assertCommandCheckOutput(a, "aaaa", assertStartsWith("| Error:")), @@ -730,23 +726,6 @@ public class ToolBasicTest extends ReplToolTesting { } } - public void testFeedbackConcise() { - Compiler compiler = new Compiler(); - Path testConciseFile = compiler.getPath("testConciseFeedback"); - String[] sources = new String[] {"int a", "void f() {}", "class A {}", "a = 10"}; - compiler.writeToFile(testConciseFile, sources); - for (String concise : new String[]{"c", "concise"}) { - test( - a -> assertCommand(a, "/feedback " + concise, ""), - a -> assertCommand(a, sources[0], ""), - a -> assertCommand(a, sources[1], ""), - a -> assertCommand(a, sources[2], ""), - a -> assertCommand(a, sources[3], "| a : 10\n"), - a -> assertCommand(a, "/o " + testConciseFile.toString(), "| a : 10\n") - ); - } - } - public void testFeedbackNormal() { Compiler compiler = new Compiler(); Path testNormalFile = compiler.getPath("testConciseNormal"); @@ -759,58 +738,20 @@ public class ToolBasicTest extends ReplToolTesting { "| Variable a has been assigned the value 10\n" }; compiler.writeToFile(testNormalFile, sources2); - for (String feedback : new String[]{"/f", "/feedback"}) { - for (String feedbackState : new String[]{"n", "normal", "v", "verbose"}) { - String f = null; - if (feedbackState.startsWith("n")) { - f = "normal"; - } else if (feedbackState.startsWith("v")) { - f = "verbose"; - } - final String finalF = f; + for (String feedback : new String[]{"/set f", "/set feedback"}) { + for (String feedbackState : new String[]{"n", "normal", "o", "off"}) { test( - a -> assertCommand(a, feedback + " " + feedbackState, "| Feedback mode: " + finalF +"\n"), + a -> assertCommand(a, feedback + " " + feedbackState, "| Feedback mode: normal\n"), a -> assertCommand(a, sources[0], output[0]), a -> assertCommand(a, sources[1], output[1]), a -> assertCommand(a, sources[2], output[2]), a -> assertCommand(a, sources[3], output[3]), - a -> assertCommand(a, "/o " + testNormalFile.toString(), - "| Modified variable a of type int\n" + - "| Modified method f()\n" + - "| Update overwrote method f()\n" + - "| Modified class A\n" + - "| Update overwrote class A\n" + - "| Variable a has been assigned the value 10\n") + a -> assertCommand(a, "/o " + testNormalFile.toString(), "") ); } } } - public void testFeedbackDefault() { - Compiler compiler = new Compiler(); - Path testDefaultFile = compiler.getPath("testDefaultFeedback"); - String[] sources = new String[] {"int a", "void f() {}", "class A {}", "a = 10"}; - String[] output = new String[] { - "| Added variable a of type int\n", - "| Added method f()\n", - "| Added class A\n", - "| Variable a has been assigned the value 10\n" - }; - compiler.writeToFile(testDefaultFile, sources); - for (String defaultFeedback : new String[]{"", "d", "default"}) { - test( - a -> assertCommand(a, "/feedback o", ""), - a -> assertCommand(a, "int x", ""), - a -> assertCommand(a, "/feedback " + defaultFeedback, "| Feedback mode: default\n"), - a -> assertCommand(a, sources[0], output[0]), - a -> assertCommand(a, sources[1], output[1]), - a -> assertCommand(a, sources[2], output[2]), - a -> assertCommand(a, sources[3], output[3]), - a -> assertCommand(a, "/o " + testDefaultFile.toString(), "") - ); - } - } - public void testDrop() { test(false, new String[]{"-nostartup"}, a -> assertVariable(a, "int", "a"), @@ -906,7 +847,7 @@ public class ToolBasicTest extends ReplToolTesting { public void testCommandPrefix() { test(a -> assertCommandCheckOutput(a, "/s", - assertStartsWith("| Command: /s is ambiguous: /seteditor, /save, /setstart")), + assertStartsWith("| Command: /s is ambiguous: /save, /set")), a -> assertCommand(a, "int var", "| Added variable var of type int\n"), a -> assertCommandCheckOutput(a, "/va", assertStartsWith("| int var = 0")), diff --git a/langtools/test/jdk/jshell/ToolFormatTest.java b/langtools/test/jdk/jshell/ToolFormatTest.java new file mode 100644 index 00000000000..cc3aa0273af --- /dev/null +++ b/langtools/test/jdk/jshell/ToolFormatTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8148316 8148317 + * @summary Tests for output customization + * @library /tools/lib + * @build KullaTesting TestingInputStream ToolBox Compiler + * @run testng ToolFormatTest + */ +import org.testng.annotations.Test; + +@Test +public class ToolFormatTest extends ReplToolTesting { + + public void testSetFormat() { + try { + test( + (a) -> assertCommandOutputStartsWith(a, "/set newmode test command", "| Created new feedback mode: test"), + (a) -> assertCommand(a, "/set field test pre '$ '", ""), + (a) -> assertCommand(a, "/set field test post ''", ""), + (a) -> assertCommand(a, "/set field test action 'ADD ' added-primary", ""), + (a) -> assertCommand(a, "/set field test action 'MOD ' modified-primary", ""), + (a) -> assertCommand(a, "/set field test action 'REP ' replaced-primary", ""), + (a) -> assertCommand(a, "/set field test action 'UP-ADD ' added-update", ""), + (a) -> assertCommand(a, "/set field test action 'UP-MOD ' modified-update", ""), + (a) -> assertCommand(a, "/set field test action 'UP-REP ' replaced-update", ""), + (a) -> assertCommand(a, "/set field test resolve 'OK' ok-*", ""), + (a) -> assertCommand(a, "/set field test resolve 'DEF' defined-*", ""), + (a) -> assertCommand(a, "/set field test resolve 'NODEF' notdefined-*", ""), + (a) -> assertCommand(a, "/set field test name ':%s ' ", ""), + (a) -> assertCommand(a, "/set field test type '[%s]' ", ""), + (a) -> assertCommand(a, "/set field test result '=%s ' ", ""), + (a) -> assertCommand(a, "/set format test '{pre}{action}{type}{name}{result}{resolve}' *-*-*", ""), + (a) -> assertCommand(a, "/set format test '{pre}HI this is enum' enum", ""), + (a) -> assertCommand(a, "/set feedback test", "$ Feedback mode: test"), + (a) -> assertCommand(a, "class D {}", "$ ADD :D OK"), + (a) -> assertCommand(a, "void m() {}", "$ ADD []:m OK"), + (a) -> assertCommand(a, "interface EX extends EEX {}", "$ ADD :EX NODEF"), + (a) -> assertCommand(a, "56", "$ ADD [int]:$4 =56 OK"), + (a) -> assertCommand(a, "class D { int hh; }", "$ REP :D OK$ OVERWROTE-UPDATE:D OK"), + (a) -> assertCommandOutputStartsWith(a, "/set feedback normal", "| Feedback mode: normal") + ); + } finally { + assertCommandCheckOutput(false, "/set feedback normal", s -> { + }); + } + } + + public void testNewModeQuiet() { + try { + test( + (a) -> assertCommandOutputStartsWith(a, "/set newmode nmq quiet normal", "| Created new feedback mode: nmq"), + (a) -> assertCommand(a, "/set feedback nmq", ""), + (a) -> assertCommand(a, "/se ne nmq2 q nor", ""), + (a) -> assertCommand(a, "/se fee nmq2", ""), + (a) -> assertCommand(a, "/set newmode nmc command normal", ""), + (a) -> assertCommandOutputStartsWith(a, "/set feedback nmc", "| Feedback mode: nmc"), + (a) -> assertCommandOutputStartsWith(a, "/set newmode nm", "| Created new feedback mode: nm"), + (a) -> assertCommandOutputStartsWith(a, "/set feedback nm", "| Feedback mode: nm") + ); + } finally { + assertCommandCheckOutput(false, "/set feedback normal", s -> { + }); + } + } + + public void testSetError() { + try { + test( + (a) -> assertCommandOutputStartsWith(a, "/set newmode te command normal", "| Created new feedback mode: te"), + (a) -> assertCommand(a, "/set field te errorpre 'ERROR: '", ""), + (a) -> assertCommandOutputStartsWith(a, "/set feedback te", ""), + (a) -> assertCommandCheckOutput(a, "/set ", assertStartsWith("ERROR: The /set command requires arguments")), + (a) -> assertCommandCheckOutput(a, "/set xyz", assertStartsWith("ERROR: Not a valid argument to /set")), + (a) -> assertCommandCheckOutput(a, "/set f", assertStartsWith("ERROR: Ambiguous argument to /set")), + (a) -> assertCommandCheckOutput(a, "/set feedback", assertStartsWith("ERROR: Expected a feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set feedback xyz", assertStartsWith("ERROR: Does not match any current feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set format", assertStartsWith("ERROR: Expected a feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set format xyz", assertStartsWith("ERROR: Does not match any current feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set format te", assertStartsWith("ERROR: Expected format missing")), + (a) -> assertCommandCheckOutput(a, "/set format te aaa", assertStartsWith("ERROR: Format 'aaa' must be quoted")), + (a) -> assertCommandCheckOutput(a, "/set format te 'aaa'", assertStartsWith("ERROR: At least one selector required")), + (a) -> assertCommandCheckOutput(a, "/set format te 'aaa' frog", assertStartsWith("ERROR: Not a valid case")), + (a) -> assertCommandCheckOutput(a, "/set format te 'aaa' import-frog", assertStartsWith("ERROR: Not a valid action")), + (a) -> assertCommandCheckOutput(a, "/set newmode", assertStartsWith("ERROR: Expected new feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set newmode te", assertStartsWith("ERROR: Expected a new feedback mode name")), + (a) -> assertCommandCheckOutput(a, "/set newmode x xyz", assertStartsWith("ERROR: Specify either 'command' or 'quiet'")), + (a) -> assertCommandCheckOutput(a, "/set newmode x quiet y", assertStartsWith("ERROR: Does not match any current feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set prompt", assertStartsWith("ERROR: Expected a feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set prompt te", assertStartsWith("ERROR: Expected format missing")), + (a) -> assertCommandCheckOutput(a, "/set prompt te aaa xyz", assertStartsWith("ERROR: Format 'aaa' must be quoted")), + (a) -> assertCommandCheckOutput(a, "/set prompt te 'aaa' xyz", assertStartsWith("ERROR: Format 'xyz' must be quoted")), + (a) -> assertCommandCheckOutput(a, "/set prompt", assertStartsWith("ERROR: Expected a feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set prompt te", assertStartsWith("ERROR: Expected format missing")), + (a) -> assertCommandCheckOutput(a, "/set prompt te aaa", assertStartsWith("ERROR: Format 'aaa' must be quoted")), + (a) -> assertCommandCheckOutput(a, "/set prompt te 'aaa'", assertStartsWith("ERROR: Expected format missing")), + (a) -> assertCommandCheckOutput(a, "/set field", assertStartsWith("ERROR: Expected a feedback mode")), + (a) -> assertCommandCheckOutput(a, "/set field xyz", assertStartsWith("ERROR: Does not match any current feedback mode: xyz")), + (a) -> assertCommandCheckOutput(a, "/set field te xyz", assertStartsWith("ERROR: Not a valid field: xyz, must be one of: when")), + (a) -> assertCommandCheckOutput(a, "/set field te action", assertStartsWith("ERROR: Expected format missing")), + (a) -> assertCommandCheckOutput(a, "/set field te action 'act'", assertStartsWith("ERROR: At least one selector required")) + ); + } finally { + assertCommandCheckOutput(false, "/set feedback normal", s -> { + }); + } + } + + public void testSetHelp() { + try { + test( + (a) -> assertCommandOutputContains(a, "/help /set", "command to launch"), + (a) -> assertCommandOutputContains(a, "/help /set format", "vardecl"), + (a) -> assertCommandOutputContains(a, "/hel /se for", "vardecl"), + (a) -> assertCommandOutputContains(a, "/help /set editor", "temporary file") + ); + } finally { + assertCommandCheckOutput(false, "/set feedback normal", s -> { + }); + } + } + + public void testSetHelpError() { + try { + test( + (a) -> assertCommandOutputStartsWith(a, "/set newmode te command normal", "| Created new feedback mode: te"), + (a) -> assertCommand(a, "/set field te errorpre 'ERROR: '", ""), + (a) -> assertCommandOutputStartsWith(a, "/set feedback te", "| Feedback mode: te"), + (a) -> assertCommandOutputContains(a, "/help /set xyz", "ERROR: Not a valid argument to /set: xyz"), + (a) -> assertCommandOutputContains(a, "/help /set f", "ERROR: Ambiguous argument to /set: f") + ); + } finally { + assertCommandCheckOutput(false, "/set feedback normal", s -> { + }); + } + } +} From a0224437fcc150c04c75de8ca162d91324e3296d Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 9 Mar 2016 12:52:14 +0300 Subject: [PATCH 065/183] 8151223: String concatenation fails with implicit toString() on package-private class Reviewed-by: mcimadamore, forax --- .../com/sun/tools/javac/jvm/StringConcat.java | 26 ++- .../javac/StringConcat/access/Holder.java | 98 +++++++++ .../StringConcat/access/PublicClass.java | 27 +++ .../StringConcat/access/PublicInterface.java | 27 +++ .../access/Public_PrivateInterface1.java | 30 +++ .../access/Public_PrivateInterface2.java | 30 +++ .../access/Public_PublicClass.java | 30 +++ .../access/Public_PublicInterface.java | 30 +++ .../tools/javac/StringConcat/access/Test.java | 192 ++++++++++++++++++ 9 files changed, 486 insertions(+), 4 deletions(-) create mode 100644 langtools/test/tools/javac/StringConcat/access/Holder.java create mode 100644 langtools/test/tools/javac/StringConcat/access/PublicClass.java create mode 100644 langtools/test/tools/javac/StringConcat/access/PublicInterface.java create mode 100644 langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface1.java create mode 100644 langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface2.java create mode 100644 langtools/test/tools/javac/StringConcat/access/Public_PublicClass.java create mode 100644 langtools/test/tools/javac/StringConcat/access/Public_PublicInterface.java create mode 100644 langtools/test/tools/javac/StringConcat/access/Test.java diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java index bb5436bd96c..80cee302dec 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java @@ -33,8 +33,7 @@ import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.*; import static com.sun.tools.javac.code.Kinds.Kind.MTH; -import static com.sun.tools.javac.code.TypeTag.DOUBLE; -import static com.sun.tools.javac.code.TypeTag.LONG; +import static com.sun.tools.javac.code.TypeTag.*; import static com.sun.tools.javac.jvm.ByteCodes.*; import static com.sun.tools.javac.tree.JCTree.Tag.PLUS; import com.sun.tools.javac.jvm.Items.*; @@ -142,6 +141,25 @@ public abstract class StringConcat { return res.append(tree); } + /** + * If the type is not accessible from current context, try to figure out the + * sharpest accessible supertype. + * + * @param originalType type to sharpen + * @return sharped type + */ + Type sharpestAccessible(Type originalType) { + if (originalType.hasTag(ARRAY)) { + return types.makeArrayType(sharpestAccessible(types.elemtype(originalType))); + } + + Type type = originalType; + while (!rs.isAccessible(gen.getAttrEnv(), type.asElement())) { + type = types.supertype(type); + } + return type; + } + /** * "Legacy" bytecode flavor: emit the StringBuilder.append chains for string * concatenation. @@ -314,7 +332,7 @@ public abstract class StringConcat { if (arg.type == syms.botType) { dynamicArgs.add(types.boxedClass(syms.voidType).type); } else { - dynamicArgs.add(arg.type); + dynamicArgs.add(sharpestAccessible(arg.type)); } gen.genExpr(arg, arg.type).load(); } @@ -415,7 +433,7 @@ public abstract class StringConcat { } else { // Ordinary arguments come through the dynamic arguments. recipe.append(TAG_ARG); - dynamicArgs.add(arg.type); + dynamicArgs.add(sharpestAccessible(arg.type)); gen.genExpr(arg, arg.type).load(); } } diff --git a/langtools/test/tools/javac/StringConcat/access/Holder.java b/langtools/test/tools/javac/StringConcat/access/Holder.java new file mode 100644 index 00000000000..6b4cb37e688 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/Holder.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2016, 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. + */ + +package p1; + +public class Holder { + public Private_PublicClass c1 = new Private_PublicClass(); + public Private_PublicInterface c2 = new Private_PublicInterface(); + public Private_PrivateInterface1 c3 = new Private_PrivateInterface1(); + public Private_PrivateInterface2 c4 = new Private_PrivateInterface2(); + + public Public_PublicClass c5 = new Public_PublicClass(); + public Public_PublicInterface c6 = new Public_PublicInterface(); + public Public_PrivateInterface1 c7 = new Public_PrivateInterface1(); + public Public_PrivateInterface2 c8 = new Public_PrivateInterface2(); + + public Private_PublicClass[] ac1 = new Private_PublicClass[0]; + public Private_PublicInterface[] ac2 = new Private_PublicInterface[0]; + public Private_PrivateInterface1[] ac3 = new Private_PrivateInterface1[0]; + public Private_PrivateInterface2[] ac4 = new Private_PrivateInterface2[0]; + + public Public_PublicClass[] ac5 = new Public_PublicClass[0]; + public Public_PublicInterface[] ac6 = new Public_PublicInterface[0]; + public Public_PrivateInterface1[] ac7 = new Public_PrivateInterface1[0]; + public Public_PrivateInterface2[] ac8 = new Public_PrivateInterface2[0]; + + public Private_PublicClass[][] aac1 = new Private_PublicClass[0][]; + public Private_PublicInterface[][] aac2 = new Private_PublicInterface[0][]; + public Private_PrivateInterface1[][] aac3 = new Private_PrivateInterface1[0][]; + public Private_PrivateInterface2[][] aac4 = new Private_PrivateInterface2[0][]; + + public Public_PublicClass[][] aac5 = new Public_PublicClass[0][]; + public Public_PublicInterface[][] aac6 = new Public_PublicInterface[0][]; + public Public_PrivateInterface1[][] aac7 = new Public_PrivateInterface1[0][]; + public Public_PrivateInterface2[][] aac8 = new Public_PrivateInterface2[0][]; + + public PublicInterface i1 = new Private_PublicInterface(); + public PrivateInterface1 i2 = new Private_PrivateInterface1(); + public PrivateInterface2 i3 = new Private_PrivateInterface2(); + + public PublicInterface[] ai1 = new Private_PublicInterface[0]; + public PrivateInterface1[] ai2 = new Private_PrivateInterface1[0]; + public PrivateInterface2[] ai3 = new Private_PrivateInterface2[0]; + + public PublicInterface[][] aai1 = new Private_PublicInterface[0][]; + public PrivateInterface1[][] aai2 = new Private_PrivateInterface1[0][]; + public PrivateInterface2[][] aai3 = new Private_PrivateInterface2[0][]; +} + +interface PrivateInterface1 { +} + +interface PrivateInterface2 extends PublicInterface { +} + +class Private_PublicClass extends PublicClass { + public String toString() { + return "passed"; + } +} + +class Private_PublicInterface implements PublicInterface { + public String toString() { + return "passed"; + } +} + +class Private_PrivateInterface1 implements PrivateInterface1 { + public String toString() { + return "passed"; + } +} + +class Private_PrivateInterface2 implements PrivateInterface2 { + public String toString() { + return "passed"; + } +} diff --git a/langtools/test/tools/javac/StringConcat/access/PublicClass.java b/langtools/test/tools/javac/StringConcat/access/PublicClass.java new file mode 100644 index 00000000000..d4ae6bfc36e --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/PublicClass.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, 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. + */ + +package p1; + +public class PublicClass { +} diff --git a/langtools/test/tools/javac/StringConcat/access/PublicInterface.java b/langtools/test/tools/javac/StringConcat/access/PublicInterface.java new file mode 100644 index 00000000000..ba26be94955 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/PublicInterface.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, 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. + */ + +package p1; + +public interface PublicInterface { +} diff --git a/langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface1.java b/langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface1.java new file mode 100644 index 00000000000..301f90ec798 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface1.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, 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. + */ + +package p1; + +public class Public_PrivateInterface1 implements PrivateInterface1 { + public String toString() { + return "passed"; + } +} diff --git a/langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface2.java b/langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface2.java new file mode 100644 index 00000000000..dcfcea14ad4 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/Public_PrivateInterface2.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, 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. + */ + +package p1; + +public class Public_PrivateInterface2 implements PrivateInterface2 { + public String toString() { + return "passed"; + } +} diff --git a/langtools/test/tools/javac/StringConcat/access/Public_PublicClass.java b/langtools/test/tools/javac/StringConcat/access/Public_PublicClass.java new file mode 100644 index 00000000000..20d28acf0d3 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/Public_PublicClass.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, 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. + */ + +package p1; + +public class Public_PublicClass { + public String toString() { + return "passed"; + } +} diff --git a/langtools/test/tools/javac/StringConcat/access/Public_PublicInterface.java b/langtools/test/tools/javac/StringConcat/access/Public_PublicInterface.java new file mode 100644 index 00000000000..1c8ae4b60bd --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/Public_PublicInterface.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2016, 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. + */ + +package p1; + +public class Public_PublicInterface implements PublicInterface { + public String toString() { + return "passed"; + } +} diff --git a/langtools/test/tools/javac/StringConcat/access/Test.java b/langtools/test/tools/javac/StringConcat/access/Test.java new file mode 100644 index 00000000000..fc9e78c0e31 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/access/Test.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8151223 + * @summary String concatenation fails with implicit toString() on package-private class + * @modules jdk.jdeps/com.sun.tools.classfile + * @compile -XDstringConcat=indy Holder.java PublicClass.java PublicInterface.java Public_PublicClass.java Public_PublicInterface.java Public_PrivateInterface1.java Public_PrivateInterface2.java Test.java + * @run main Test + * @compile -XDstringConcat=indyWithConstants Holder.java PublicClass.java PublicInterface.java Public_PublicClass.java Public_PublicInterface.java Public_PrivateInterface1.java Public_PrivateInterface2.java Test.java + * @run main Test + */ + +import com.sun.tools.classfile.*; +import com.sun.tools.classfile.ConstantPool.*; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class Test { + static List actualTypes; + + public static void main(String[] argv) throws Exception { + readIndyTypes(); + + p1.Holder holder = new p1.Holder(); + + int idx = 0; + + // ---------------------------------------------------------------------------- + + // public Private_PublicClass c1 = new Private_PublicClass(); + test("" + holder.c1, idx++, "(Lp1/PublicClass;)Ljava/lang/String;"); + + // public Private_PublicInterface c2 = new Private_PublicInterface(); + test("" + holder.c2, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + + // public Private_PrivateInterface1 c3 = new Private_PrivateInterface1(); + test("" + holder.c3, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + + // public Private_PrivateInterface2 c4 = new Private_PrivateInterface2(); + test("" + holder.c4, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + + // public Public_PublicClass c5 = new Public_PublicClass(); + test("" + holder.c5, idx++, "(Lp1/Public_PublicClass;)Ljava/lang/String;"); + + // public Public_PublicInterface c6 = new Public_PublicInterface(); + test("" + holder.c6, idx++, "(Lp1/Public_PublicInterface;)Ljava/lang/String;"); + + // public Public_PrivateInterface1 c7 = new Public_PrivateInterface1(); + test("" + holder.c7, idx++, "(Lp1/Public_PrivateInterface1;)Ljava/lang/String;"); + + // public Public_PrivateInterface2 c8 = new Public_PrivateInterface2(); + test("" + holder.c8, idx++, "(Lp1/Public_PrivateInterface2;)Ljava/lang/String;"); + + // ---------------------------------------------------------------------------- + + // public Private_PublicClass[] ac1 = new Private_PublicClass[0]; + test("" + holder.ac1, idx++, "([Lp1/PublicClass;)Ljava/lang/String;"); + + // public Private_PublicInterface[] ac2 = new Private_PublicInterface[0]; + test("" + holder.ac2, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + + // public Private_PrivateInterface1[] ac3 = new Private_PrivateInterface1[0]; + test("" + holder.ac3, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + + // public Private_PrivateInterface2[] ac4 = new Private_PrivateInterface2[0]; + test("" + holder.ac4, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + + // public Public_PublicClass[] ac5 = new Public_PublicClass[0]; + test("" + holder.ac5, idx++, "([Lp1/Public_PublicClass;)Ljava/lang/String;"); + + // public Public_PublicInterface[] ac6 = new Public_PublicInterface[0]; + test("" + holder.ac6, idx++, "([Lp1/Public_PublicInterface;)Ljava/lang/String;"); + + // public Public_PrivateInterface1[] ac7 = new Public_PrivateInterface1[0]; + test("" + holder.ac7, idx++, "([Lp1/Public_PrivateInterface1;)Ljava/lang/String;"); + + // public Public_PrivateInterface2[] ac8 = new Public_PrivateInterface2[0]; + test("" + holder.ac8, idx++, "([Lp1/Public_PrivateInterface2;)Ljava/lang/String;"); + + // ---------------------------------------------------------------------------- + + // public Private_PublicClass[][] aac1 = new Private_PublicClass[0][]; + test("" + holder.aac1, idx++, "([[Lp1/PublicClass;)Ljava/lang/String;"); + + // public Private_PublicInterface[][] aac2 = new Private_PublicInterface[0][]; + test("" + holder.aac2, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + + // public Private_PrivateInterface1[][] aac3 = new Private_PrivateInterface1[0][]; + test("" + holder.aac3, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + + // public Private_PrivateInterface2[][] aac4 = new Private_PrivateInterface2[0][]; + test("" + holder.aac4, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + + // public Public_PublicClass[][] aac5 = new Public_PublicClass[0][]; + test("" + holder.aac5, idx++, "([[Lp1/Public_PublicClass;)Ljava/lang/String;"); + + // public Public_PublicInterface[][] aac6 = new Public_PublicInterface[0][]; + test("" + holder.aac6, idx++, "([[Lp1/Public_PublicInterface;)Ljava/lang/String;"); + + // public Public_PrivateInterface1[][] aac7 = new Public_PrivateInterface1[0][]; + test("" + holder.aac7, idx++, "([[Lp1/Public_PrivateInterface1;)Ljava/lang/String;"); + + // public Public_PrivateInterface2[][] aac8 = new Public_PrivateInterface2[0][]; + test("" + holder.aac8, idx++, "([[Lp1/Public_PrivateInterface2;)Ljava/lang/String;"); + + // ---------------------------------------------------------------------------- + + // public PublicInterface i1 = new Private_PublicInterface(); + test("" + holder.i1, idx++, "(Lp1/PublicInterface;)Ljava/lang/String;"); + + // public PrivateInterface1 i2 = new Private_PrivateInterface1(); + test("" + holder.i2, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + + // public PrivateInterface2 i3 = new Private_PrivateInterface2(); + test("" + holder.i3, idx++, "(Ljava/lang/Object;)Ljava/lang/String;"); + + // public PublicInterface[] ai1 = new Private_PublicInterface[0]; + test("" + holder.ai1, idx++, "([Lp1/PublicInterface;)Ljava/lang/String;"); + + // public PrivateInterface1[] ai2 = new Private_PrivateInterface1[0]; + test("" + holder.ai2, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + + // public PrivateInterface2[] ai3 = new Private_PrivateInterface2[0]; + test("" + holder.ai3, idx++, "([Ljava/lang/Object;)Ljava/lang/String;"); + + // public PublicInterface[][] aai1 = new Private_PublicInterface[0][]; + test("" + holder.aai1, idx++, "([[Lp1/PublicInterface;)Ljava/lang/String;"); + + // public PrivateInterface1[][] aai2 = new Private_PrivateInterface1[0][]; + test("" + holder.aai2, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + + // public PrivateInterface2[][] aai3 = new Private_PrivateInterface2[0][]; + test("" + holder.aai3, idx++, "([[Ljava/lang/Object;)Ljava/lang/String;"); + + } + + public static void test(String actual, int index, String expectedType) { + if (!"passed".equals(actual) && !actual.startsWith("[")) { + throw new IllegalStateException("Unexpected result: " + actual); + } + String actualType = actualTypes.get(index); + if (!actualType.equals(expectedType)) { + throw new IllegalStateException("Unexpected type: expected = " + expectedType + ", actual = " + actualType); + } + } + + public static void readIndyTypes() throws Exception { + actualTypes = new ArrayList(); + + ClassFile classFile = ClassFile.read(new File(System.getProperty("test.classes", "."), + Test.class.getName() + ".class")); + ConstantPool constantPool = classFile.constant_pool; + + for (Method method : classFile.methods) { + if (method.getName(constantPool).equals("main")) { + Code_attribute code = (Code_attribute) method.attributes + .get(Attribute.Code); + for (Instruction i : code.getInstructions()) { + if (i.getOpcode() == Opcode.INVOKEDYNAMIC) { + CONSTANT_InvokeDynamic_info indyInfo = (CONSTANT_InvokeDynamic_info) constantPool.get(i.getUnsignedShort(1)); + CONSTANT_NameAndType_info natInfo = indyInfo.getNameAndTypeInfo(); + actualTypes.add(natInfo.getType()); + } + } + } + } + } +} From 0a352526f390f8d204ccdeace3b3fdddcd47b017 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 9 Mar 2016 18:31:49 +0300 Subject: [PATCH 066/183] 8151516: test/tools/javac/TestIndyStringConcat depends on runtime JDK details Reviewed-by: mcimadamore --- .../StringConcat/TestIndyStringConcat.java | 111 ++++++++++++++++++ .../tools/javac/StringConcat/access/Test.java | 26 ++-- .../tools/javac/TestIndyStringConcat.java | 74 ------------ 3 files changed, 126 insertions(+), 85 deletions(-) create mode 100644 langtools/test/tools/javac/StringConcat/TestIndyStringConcat.java delete mode 100644 langtools/test/tools/javac/TestIndyStringConcat.java diff --git a/langtools/test/tools/javac/StringConcat/TestIndyStringConcat.java b/langtools/test/tools/javac/StringConcat/TestIndyStringConcat.java new file mode 100644 index 00000000000..4c8917bbbf9 --- /dev/null +++ b/langtools/test/tools/javac/StringConcat/TestIndyStringConcat.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015, 2016, 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 com.sun.tools.classfile.*; +import com.sun.tools.classfile.BootstrapMethods_attribute.BootstrapMethodSpecifier; +import com.sun.tools.classfile.ConstantPool.CONSTANT_InvokeDynamic_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodHandle_info; + +import java.io.File; + +/* + * @test + * @bug 8148483 8151516 8151223 + * @summary Test that StringConcat is working for JDK >= 9 + * @modules jdk.jdeps/com.sun.tools.classfile + * + * @clean TestIndyStringConcat* + * @compile -source 6 -target 6 TestIndyStringConcat.java + * @run main TestIndyStringConcat false + * + * @clean TestIndyStringConcat* + * @compile -source 7 -target 7 TestIndyStringConcat.java + * @run main TestIndyStringConcat false + * + * @clean TestIndyStringConcat* + * @compile -source 8 -target 8 TestIndyStringConcat.java + * @run main TestIndyStringConcat false + * + * @clean TestIndyStringConcat* + * @compile -XDstringConcat=inline -source 9 -target 9 TestIndyStringConcat.java + * @run main TestIndyStringConcat false + * + * @clean TestIndyStringConcat* + * @compile -XDstringConcat=indy -source 9 -target 9 TestIndyStringConcat.java + * @run main TestIndyStringConcat true + * + * @clean TestIndyStringConcat* + * @compile -XDstringConcat=indyWithConstants -source 9 -target 9 TestIndyStringConcat.java + * @run main TestIndyStringConcat true + */ +public class TestIndyStringConcat { + + static String other; + + public static String test() { + return "Foo" + other; + } + + public static void main(String[] args) throws Exception { + boolean expected = Boolean.valueOf(args[0]); + boolean actual = hasStringConcatFactoryCall("test"); + if (expected != actual) { + throw new AssertionError("expected = " + expected + ", actual = " + actual); + } + } + + public static boolean hasStringConcatFactoryCall(String methodName) throws Exception { + ClassFile classFile = ClassFile.read(new File(System.getProperty("test.classes", "."), + TestIndyStringConcat.class.getName() + ".class")); + ConstantPool constantPool = classFile.constant_pool; + + BootstrapMethods_attribute bsm_attr = + (BootstrapMethods_attribute)classFile + .getAttribute(Attribute.BootstrapMethods); + + for (Method method : classFile.methods) { + if (method.getName(constantPool).equals(methodName)) { + Code_attribute code = (Code_attribute) method.attributes + .get(Attribute.Code); + for (Instruction i : code.getInstructions()) { + if (i.getOpcode() == Opcode.INVOKEDYNAMIC) { + CONSTANT_InvokeDynamic_info indyInfo = + (CONSTANT_InvokeDynamic_info) constantPool.get(i.getUnsignedShort(1)); + + BootstrapMethodSpecifier bsmSpec = + bsm_attr.bootstrap_method_specifiers[indyInfo.bootstrap_method_attr_index]; + + CONSTANT_MethodHandle_info bsmInfo = + (CONSTANT_MethodHandle_info) constantPool.get(bsmSpec.bootstrap_method_ref); + + if (bsmInfo.getCPRefInfo().getClassName().equals("java/lang/invoke/StringConcatFactory")) { + return true; + } + } + } + } + } + return false; + } + +} diff --git a/langtools/test/tools/javac/StringConcat/access/Test.java b/langtools/test/tools/javac/StringConcat/access/Test.java index fc9e78c0e31..72237e8b4ef 100644 --- a/langtools/test/tools/javac/StringConcat/access/Test.java +++ b/langtools/test/tools/javac/StringConcat/access/Test.java @@ -21,17 +21,6 @@ * questions. */ -/* - * @test - * @bug 8151223 - * @summary String concatenation fails with implicit toString() on package-private class - * @modules jdk.jdeps/com.sun.tools.classfile - * @compile -XDstringConcat=indy Holder.java PublicClass.java PublicInterface.java Public_PublicClass.java Public_PublicInterface.java Public_PrivateInterface1.java Public_PrivateInterface2.java Test.java - * @run main Test - * @compile -XDstringConcat=indyWithConstants Holder.java PublicClass.java PublicInterface.java Public_PublicClass.java Public_PublicInterface.java Public_PrivateInterface1.java Public_PrivateInterface2.java Test.java - * @run main Test - */ - import com.sun.tools.classfile.*; import com.sun.tools.classfile.ConstantPool.*; @@ -39,6 +28,21 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +/* + * @test + * @bug 8151223 + * @summary String concatenation fails with implicit toString() on package-private class + * @modules jdk.jdeps/com.sun.tools.classfile + * + * @clean * + * @compile -XDstringConcat=indy Holder.java PublicClass.java PublicInterface.java Public_PublicClass.java Public_PublicInterface.java Public_PrivateInterface1.java Public_PrivateInterface2.java Test.java + * @run main Test + * + * @clean * + * @compile -XDstringConcat=indyWithConstants Holder.java PublicClass.java PublicInterface.java Public_PublicClass.java Public_PublicInterface.java Public_PrivateInterface1.java Public_PrivateInterface2.java Test.java + * @run main Test + */ + public class Test { static List actualTypes; diff --git a/langtools/test/tools/javac/TestIndyStringConcat.java b/langtools/test/tools/javac/TestIndyStringConcat.java deleted file mode 100644 index b799f70015b..00000000000 --- a/langtools/test/tools/javac/TestIndyStringConcat.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @summary Test that StringConcat is working for JDK >= 9 - * @compile -source 6 -target 6 TestIndyStringConcat.java - * @run main TestIndyStringConcat false - * @clean TestIndyStringConcat* - * @compile -source 7 -target 7 TestIndyStringConcat.java - * @run main TestIndyStringConcat false - * @clean TestIndyStringConcat* - * @compile -source 8 -target 8 TestIndyStringConcat.java - * @run main TestIndyStringConcat false - * @clean TestIndyStringConcat* - * @compile -XDstringConcat=inline -source 9 -target 9 TestIndyStringConcat.java - * @run main TestIndyStringConcat false - * @clean TestIndyStringConcat* - * @compile -XDstringConcat=indy -source 9 -target 9 TestIndyStringConcat.java - * @run main TestIndyStringConcat true - * @clean TestIndyStringConcat* - * @compile -XDstringConcat=indyWithConstants -source 9 -target 9 TestIndyStringConcat.java - * @run main TestIndyStringConcat true - */ -public class TestIndyStringConcat { - - private static class MyObject { - public String toString() { - throw new RuntimeException("Boyyaa"); - } - } - - class Inner { } - - public static void main(String[] args) { - boolean useIndyConcat = Boolean.valueOf(args[0]); - try { - String s = "Foo" + new MyObject(); - } catch (RuntimeException ex) { - boolean indifiedStringConcat = false; - ex.printStackTrace(); - for (StackTraceElement e : ex.getStackTrace()) { - if (e.getClassName().contains("$$StringConcat") && - e.getMethodName().equals("concat")) { - indifiedStringConcat = true; - break; - } - } - if (indifiedStringConcat != useIndyConcat) { - throw new AssertionError(); - } - } - } -} From eb9a8ddcc4d2f3bcad1acb33198cfe53ba8aa18c Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Thu, 10 Mar 2016 08:54:29 +0100 Subject: [PATCH 067/183] 8150632: jdk.jshell.TaskFactory should use jdk.Version to check for java.specification.version Reviewed-by: rfield --- .../src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java index 0582fd66cae..f27b0c770be 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java @@ -61,6 +61,7 @@ import javax.lang.model.util.Elements; import javax.tools.FileObject; import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject; import jdk.jshell.ClassTracker.ClassInfo; +import jdk.Version; /** * The primary interface to the compiler API. Parsing, analysis, and @@ -73,6 +74,7 @@ class TaskFactory { private final MemoryFileManager fileManager; private final JShell state; private String classpath = System.getProperty("java.class.path"); + private final static Version INITIAL_SUPPORTED_VER = Version.parse("9"); TaskFactory(JShell state) { this.state = state; @@ -80,7 +82,8 @@ class TaskFactory { if (compiler == null) { throw new UnsupportedOperationException("Compiler not available, must be run with full JDK 9."); } - if (!System.getProperty("java.specification.version").equals("9")) { + Version current = Version.parse(System.getProperty("java.specification.version")); + if (INITIAL_SUPPORTED_VER.compareToIgnoreOpt(current) > 0) { throw new UnsupportedOperationException("Wrong compiler, must be run with full JDK 9."); } this.fileManager = new MemoryFileManager( From c66a688da238dca67f2c8981ad701de8cf4af382 Mon Sep 17 00:00:00 2001 From: Lana Steuck Date: Thu, 10 Mar 2016 09:28:19 -0800 Subject: [PATCH 068/183] Added tag jdk-9+109 for changeset f74f056dc069 --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index 08776ccc375..5fb34d8884a 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -351,3 +351,4 @@ cb73b474703e2de266542b505cffd658bcc052da jdk-9+99 dd05d3761a341143ef4a6b1a245e0960cc125b76 jdk-9+106 7a0c343551497bd0e38ad69a77cc57d9f396615a jdk-9+107 fd18a155ad22f62e06a9b74850ab8609d415c752 jdk-9+108 +f5991c73ed73b9a355a090b65c8d7fb9a1901f89 jdk-9+109 From 19e4c511578a846d781ed5cbaf947165409b138d Mon Sep 17 00:00:00 2001 From: Robert Field Date: Thu, 10 Mar 2016 14:47:14 -0800 Subject: [PATCH 069/183] 8080069: JShell: Support for corralled classes Reviewed-by: jlahoda --- .../jdk/internal/jshell/tool/JShellTool.java | 8 +- .../share/classes/jdk/jshell/Corraller.java | 148 ++++++++++++ .../share/classes/jdk/jshell/Eval.java | 11 +- .../classes/jdk/jshell/ExecutionControl.java | 2 +- .../jshell/UnresolvedReferenceException.java | 24 +- .../share/classes/jdk/jshell/Wrap.java | 92 +++++++- langtools/test/jdk/jshell/ClassesTest.java | 9 +- langtools/test/jdk/jshell/DropTest.java | 36 +-- langtools/test/jdk/jshell/KullaTesting.java | 12 +- langtools/test/jdk/jshell/ReplaceTest.java | 215 +++++++++++++----- 10 files changed, 439 insertions(+), 118 deletions(-) create mode 100644 langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java diff --git a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java index 10b121b4062..55eb01bb908 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java @@ -98,6 +98,7 @@ import jdk.internal.jshell.tool.Feedback.FormatCase; import jdk.internal.jshell.tool.Feedback.FormatResolve; import jdk.internal.jshell.tool.Feedback.FormatWhen; import static java.util.stream.Collectors.toList; +import static jdk.jshell.Snippet.Kind.METHOD; import static java.util.stream.Collectors.toMap; import static jdk.jshell.Snippet.SubKind.VAR_VALUE_SUBKIND; @@ -2139,7 +2140,7 @@ public class JShellTool { } //where void printUnresolved(UnresolvedReferenceException ex) { - MethodSnippet corralled = ex.getMethodSnippet(); + DeclarationSnippet corralled = ex.getSnippet(); List otherErrors = errorsOnly(state.diagnostics(corralled)); StringBuilder sb = new StringBuilder(); if (otherErrors.size() > 0) { @@ -2155,7 +2156,10 @@ public class JShellTool { sb.append("."); } - hard("Attempted to call %s which cannot be invoked until%s", corralled.name(), + String format = corralled.kind() == METHOD + ? "Attempted to call %s which cannot be invoked until%s" + : "Attempted to use %s which cannot be accessed until%s"; + hard(format, corralled.name(), unresolved(corralled), sb.toString()); if (otherErrors.size() > 0) { printDiagnostics(corralled.source(), otherErrors, true); diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java new file mode 100644 index 00000000000..349e393caa0 --- /dev/null +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Corraller.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2016, 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 jdk.jshell; + +import java.util.List; +import com.sun.source.tree.ArrayTypeTree; +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.ExpressionTree; +import com.sun.source.tree.MethodTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.VariableTree; +import jdk.jshell.Wrap.Range; +import static java.util.stream.Collectors.toList; + +/** + * Produce a corralled version of the Wrap for a snippet. + * + * @author Robert Field + */ +class Corraller { + + private final int index; + private final String compileSource; + private final TreeDissector dis; + + Corraller(int index, String compileSource, TreeDissector dis) { + this.index = index; + this.compileSource = compileSource; + this.dis = dis; + } + + Wrap corralTree(Tree tree, String enclosingType, int indent) { + switch (tree.getKind()) { + case VARIABLE: + return corralVariable((VariableTree) tree, indent); + case CLASS: + case ENUM: + case ANNOTATION_TYPE: + case INTERFACE: + return corralType((ClassTree) tree, indent); + case METHOD: + return corralMethod((MethodTree) tree, enclosingType, indent); + default: + return null; + } + } + + Wrap corralMethod(MethodTree mt) { + return corralMethod(mt, null, 1); + } + + Wrap corralMethod(MethodTree mt, String enclosingType, int indent) { + Range modRange = dis.treeToRange(mt.getModifiers()); + Range tpRange = dis.treeListToRange(mt.getTypeParameters()); + Range typeRange = dis.treeToRange(mt.getReturnType()); + String name = mt.getName().toString(); + if ("".equals(name)) { + name = enclosingType; + } + Range paramRange = dis.treeListToRange(mt.getParameters()); + Range throwsRange = dis.treeListToRange(mt.getThrows()); + return Wrap.corralledMethod(compileSource, + modRange, tpRange, typeRange, name, paramRange, throwsRange, index, indent); + } + + Wrap corralVariable(VariableTree vt, int indent) { + String name = vt.getName().toString(); + Range modRange = dis.treeToRange(vt.getModifiers()); + Tree baseType = vt.getType(); + StringBuilder sbBrackets = new StringBuilder(); + while (baseType instanceof ArrayTypeTree) { + //TODO handle annotations too + baseType = ((ArrayTypeTree) baseType).getType(); + sbBrackets.append("[]"); + } + Range rtype = dis.treeToRange(baseType); + Range runit = dis.treeToRange(vt); + runit = new Range(runit.begin, runit.end - 1); + ExpressionTree it = vt.getInitializer(); + int nameMax; + if (it != null) { + Range rinit = dis.treeToRange(it); + nameMax = rinit.begin - 1; + } else { + nameMax = runit.end - 1; + } + int nameStart = compileSource.lastIndexOf(name, nameMax); + if (nameStart < 0) { + throw new AssertionError("Name '" + name + "' not found"); + } + int nameEnd = nameStart + name.length(); + Range rname = new Range(nameStart, nameEnd); + return Wrap.corralledVar(compileSource, modRange, rtype, sbBrackets.toString(), rname, indent); + } + + Wrap corralType(ClassTree ct, int indent) { + boolean isClass; + switch (ct.getKind()) { + case CLASS: + isClass = true; + break; + case INTERFACE: + isClass = false; + break; + default: + return null; + } + Range modRange = dis.treeToRange(ct.getModifiers()); + String name = ct.getSimpleName().toString(); + Range tpRange = dis.treeListToRange(ct.getTypeParameters()); + Range extendsRange = dis.treeToRange(ct.getExtendsClause()); + List implementsRanges = ct.getImplementsClause().stream() + .map(ic -> dis.treeToRange(ic)) + .collect(toList()); + List members = ct.getMembers().stream() + .map(t -> corralTree(t, name, indent + 1)) + .filter(w -> w != null) + .collect(toList()); + boolean hasConstructor = ct.getMembers().stream() + .anyMatch(t -> t.getKind() == Tree.Kind.METHOD && ((MethodTree) t).getName().toString().equals("")); + Wrap wrap = Wrap.corralledType(compileSource, modRange, ct.getKind(), name, tpRange, + extendsRange, implementsRanges, members, isClass && !hasConstructor, index, indent); + return wrap; + } +} diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java index 3f01908b782..610840353ec 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java @@ -53,6 +53,7 @@ import java.util.Set; import jdk.jshell.ClassTracker.ClassInfo; import jdk.jshell.Key.ErroneousKey; import jdk.jshell.Key.MethodKey; +import jdk.jshell.Key.TypeDeclKey; import jdk.jshell.Snippet.SubKind; import jdk.jshell.TaskFactory.AnalyzeTask; import jdk.jshell.TaskFactory.BaseTask; @@ -300,7 +301,8 @@ class Eval { ClassTree klassTree = (ClassTree) unitTree; String name = klassTree.getSimpleName().toString(); Wrap guts = Wrap.classMemberWrap(compileSource); - Wrap corralled = null; //TODO + TypeDeclKey key = state.keyMap.keyForClass(name); + Wrap corralled = new Corraller(key.index(), compileSource, dis).corralType(klassTree, 1); Snippet snip = new TypeDeclSnippet(state.keyMap.keyForClass(name), userSource, guts, name, snippetKind, corralled, tds.declareReferences(), tds.bodyReferences()); @@ -362,12 +364,8 @@ class Eval { String unitName = mt.getName().toString(); Wrap guts = Wrap.classMemberWrap(compileSource); - Range modRange = dis.treeToRange(mt.getModifiers()); - Range tpRange = dis.treeListToRange(mt.getTypeParameters()); Range typeRange = dis.treeToRange(mt.getReturnType()); String name = mt.getName().toString(); - Range paramRange = dis.treeListToRange(mt.getParameters()); - Range throwsRange = dis.treeListToRange(mt.getThrows()); String parameterTypes = mt.getParameters() @@ -378,8 +376,7 @@ class Eval { MethodKey key = state.keyMap.keyForMethod(name, parameterTypes); // rewrap with correct Key index - Wrap corralled = Wrap.corralledMethod(compileSource, - modRange, tpRange, typeRange, name, paramRange, throwsRange, key.index()); + Wrap corralled = new Corraller(key.index(), compileSource, dis).corralMethod(mt); Snippet snip = new MethodSnippet(key, userSource, guts, unitName, signature, corralled, tds.declareReferences(), tds.bodyReferences()); diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java index ad115656661..8f629fd75c8 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java @@ -225,7 +225,7 @@ class ExecutionControl { int id = in.readInt(); StackTraceElement[] elems = readStackTrace(); Snippet si = maps.getSnippet(id); - throw new UnresolvedReferenceException((MethodSnippet) si, elems); + throw new UnresolvedReferenceException((DeclarationSnippet) si, elems); } case RESULT_KILLED: { proc.out.println("Killed."); diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java index eaf240d47b2..3e3de8fd943 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -28,33 +28,33 @@ package jdk.jshell; /** * Exception reported on attempting to execute a * {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED} - * method. + * snippet. *

* The stack can be queried by methods on Exception. * Note that in stack trace frames representing JShell Snippets, * StackTraceElement.getFileName() will return "#" followed by * the Snippet id and for snippets without a method name (for example an - * expression) StackTraceElement.getMethodName() will be the + * expression) StackTraceElement.getName() will be the * empty string. */ @SuppressWarnings("serial") // serialVersionUID intentionally omitted public class UnresolvedReferenceException extends Exception { - final MethodSnippet methodSnippet; + final DeclarationSnippet snippet; - UnresolvedReferenceException(MethodSnippet methodSnippet, StackTraceElement[] stackElements) { - super("Attempt to invoke method with unresolved references"); - this.methodSnippet = methodSnippet; + UnresolvedReferenceException(DeclarationSnippet snippet, StackTraceElement[] stackElements) { + super("Attempt to use definition snippet with unresolved references"); + this.snippet = snippet; this.setStackTrace(stackElements); } /** - * Return the method Snippet which has the unresolved reference(s). - * @return the MethodSnippet of the + * Return the Snippet which has the unresolved reference(s). + * @return the Snippet of the * {@link jdk.jshell.Snippet.Status#RECOVERABLE_DEFINED RECOVERABLE_DEFINED} - * method. + * definition snippet. */ - public MethodSnippet getMethodSnippet() { - return methodSnippet; + public DeclarationSnippet getSnippet() { + return snippet; } } diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java index 1b380444936..62759319a9b 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -27,6 +27,7 @@ package jdk.jshell; import java.util.ArrayList; import java.util.List; +import com.sun.source.tree.Tree; import static jdk.internal.jshell.remote.RemoteCodes.DOIT_METHOD_NAME; /** @@ -58,9 +59,18 @@ abstract class Wrap implements GeneralWrap { return methodWrap("", source, ""); } - public static Wrap corralledMethod(String source, Range modRange, Range tpRange, Range typeRange, String name, Range paramRange, Range throwsRange, int id) { + private static String indent(int n) { + return " ".substring(0, n * 4); + } + + private static String nlindent(int n) { + return "\n" + indent(n); + } + + public static Wrap corralledMethod(String source, Range modRange, Range tpRange, + Range typeRange, String name, Range paramRange, Range throwsRange, int id, int indent) { List l = new ArrayList<>(); - l.add(" public static\n "); + l.add(indent(indent) + ((indent == 1) ? "public static" + nlindent(indent) : "")); if (!modRange.isEmpty()) { l.add(new RangeWrap(source, modRange)); l.add(" "); @@ -70,17 +80,81 @@ abstract class Wrap implements GeneralWrap { l.add(new RangeWrap(source, tpRange)); l.add("> "); } - l.add(new RangeWrap(source, typeRange)); - l.add(" " + name + "(\n "); - if (paramRange != null) { + if (!typeRange.isEmpty()) { + l.add(new RangeWrap(source, typeRange)); + l.add(" "); + } + l.add(name + "("); + if (paramRange != null && !paramRange.isEmpty()) { + l.add(nlindent(indent + 1)); l.add(new RangeWrap(source, paramRange)); } - l.add(") "); + l.add(")"); if (throwsRange != null) { - l.add("throws "); + l.add(" throws "); l.add(new RangeWrap(source, throwsRange)); } - l.add(" {\n throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");\n}\n"); + l.add(" {" + + nlindent(indent+1) + + "throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");" + + nlindent(indent) + + "}\n"); + return new CompoundWrap(l.toArray()); + } + + public static Wrap corralledType(String source, Range modRange, Tree.Kind kind, String name, Range tpRange, + Range extendsRange, List implementsRanges, List members, + boolean defaultConstructor, int id, int indent) { + boolean isInterface = kind == Tree.Kind.INTERFACE; + List l = new ArrayList<>(); + l.add(indent(indent) + ((indent == 1) ? "public static" + nlindent(indent) : "")); + if (!modRange.isEmpty()) { + l.add(new RangeWrap(source, modRange)); + l.add(" "); + } + l.add((isInterface ? "interface " : "class ") + name); + if (tpRange != null) { + l.add("<"); + l.add(new RangeWrap(source, tpRange)); + l.add("> "); + } + if (extendsRange != null && !extendsRange.isEmpty()) { + l.add(" extends "); + l.add(new RangeWrap(source, extendsRange)); + } + for (int i = 0; i < implementsRanges.size(); ++i) { + Range ir = implementsRanges.get(i); + l.add(i == 0 ? " implements " : ", "); + l.add(new RangeWrap(source, ir)); + } + if (defaultConstructor) { + l.add(" {" + + nlindent(indent+1) + + ((indent == 1)? "public " : "") + name + "() {" + + nlindent(indent+2) + + "throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");" + + nlindent(indent+1) + + "}\n"); + } else { + l.add(" {\n"); + } + l.addAll(members); + l.add(indent(indent) + "}\n"); + return new CompoundWrap(l.toArray()); + } + + public static Wrap corralledVar(String source, Range modRange, Range typeRange, String brackets, Range nameRange, int indent) { + RangeWrap wname = new RangeWrap(source, nameRange); + List l = new ArrayList<>(); + l.add(indent(indent) + ((indent == 1) ? "public static" + nlindent(indent) : "")); + if (!modRange.isEmpty()) { + l.add(new RangeWrap(source, modRange)); + l.add(" "); + } + l.add(new RangeWrap(source, typeRange)); + l.add(" "); + l.add(wname); + l.add(semi(wname)); return new CompoundWrap(l.toArray()); } diff --git a/langtools/test/jdk/jshell/ClassesTest.java b/langtools/test/jdk/jshell/ClassesTest.java index 394d88b3c0e..058714fe438 100644 --- a/langtools/test/jdk/jshell/ClassesTest.java +++ b/langtools/test/jdk/jshell/ClassesTest.java @@ -43,12 +43,13 @@ import org.testng.annotations.Test; import jdk.jshell.Diag; import static jdk.jshell.Snippet.Status.VALID; import static jdk.jshell.Snippet.Status.RECOVERABLE_NOT_DEFINED; +import static jdk.jshell.Snippet.Status.RECOVERABLE_DEFINED; import static jdk.jshell.Snippet.Status.DROPPED; import static jdk.jshell.Snippet.Status.REJECTED; +import static jdk.jshell.Snippet.Status.OVERWRITTEN; import static jdk.jshell.Snippet.SubKind.*; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; -import static jdk.jshell.Snippet.Status.OVERWRITTEN; @Test public class ClassesTest extends KullaTesting { @@ -82,10 +83,10 @@ public class ClassesTest extends KullaTesting { TypeDeclSnippet c1 = (TypeDeclSnippet) assertDeclareFail("class A { void f() { return g(); } }", "compiler.err.prob.found.req"); assertTypeDeclSnippet(c1, "A", REJECTED, CLASS_SUBKIND, 0, 2); TypeDeclSnippet c2 = classKey(assertEval("class A { int f() { return g(); } }", - ste(c1, REJECTED, RECOVERABLE_NOT_DEFINED, false, null))); - assertTypeDeclSnippet(c2, "A", RECOVERABLE_NOT_DEFINED, CLASS_SUBKIND, 1, 0); + ste(c1, REJECTED, RECOVERABLE_DEFINED, true, null))); + assertTypeDeclSnippet(c2, "A", RECOVERABLE_DEFINED, CLASS_SUBKIND, 1, 0); assertDrop(c2, - ste(c2, RECOVERABLE_NOT_DEFINED, DROPPED, false, null)); + ste(c2, RECOVERABLE_DEFINED, DROPPED, true, null)); } public void classDeclaration() { diff --git a/langtools/test/jdk/jshell/DropTest.java b/langtools/test/jdk/jshell/DropTest.java index 0e61ebad700..04e9fb2a4e5 100644 --- a/langtools/test/jdk/jshell/DropTest.java +++ b/langtools/test/jdk/jshell/DropTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8081431 + * @bug 8081431 8080069 * @summary Test of JShell#drop(). * @build KullaTesting TestingInputStream * @run testng DropTest @@ -31,6 +31,7 @@ import jdk.jshell.DeclarationSnippet; import jdk.jshell.PersistentSnippet; +import jdk.jshell.VarSnippet; import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.*; @@ -45,21 +46,27 @@ public class DropTest extends KullaTesting { assertDrop(var, ste(var, VALID, DROPPED, true, null), ste(method, VALID, RECOVERABLE_DEFINED, false, var)); - //assertDrop(method, - // ste(method, RECOVERABLE_DEFINED, DROPPED, false, null), - // ste(clazz, RECOVERABLE_NOT_DEFINED, RECOVERABLE_NOT_DEFINED, false, method)); - //assertDeclareFail("new C();", "compiler.err.cant.resolve.location"); + assertDrop(method, + ste(method, RECOVERABLE_DEFINED, DROPPED, true, null), + ste(clazz, VALID, RECOVERABLE_DEFINED, false, method)); + VarSnippet cc = varKey(assertEval("C c;")); + assertEvalUnresolvedException("new C();", "C", 1, 0); assertVariables(); assertMethods(); assertClasses(); assertActiveKeys(); + method = methodKey(assertEval("int mu() { return x * 4; }", + ste(MAIN_SNIPPET, DROPPED, RECOVERABLE_DEFINED, true, null), + ste(clazz, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET))); assertEval("int x = 10;", "10", - ste(var, DROPPED, VALID, true, null), + ste(MAIN_SNIPPET, DROPPED, VALID, true, null), ste(method, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET)); PersistentSnippet c0 = varKey(assertEval("C c0 = new C();")); assertEval("c0.v();", "\"#40\""); - assertEval("C c = new C();"); + assertEval("C c = new C();", + ste(MAIN_SNIPPET, VALID, VALID, false, null), + ste(cc, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); assertEval("c.v();", "\"#40\""); assertEval("int mu() { return x * 3; }", ste(MAIN_SNIPPET, VALID, VALID, false, null), @@ -144,9 +151,10 @@ public class DropTest extends KullaTesting { DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, ste(x, VALID, DROPPED, true, null), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, x)); - assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "variable x"); - assertDeclareFail("new A().a;", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, x)); + assertEval("A foo() { return null; }"); + assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable x"); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertVariables(); assertActiveKeys(); } @@ -158,9 +166,9 @@ public class DropTest extends KullaTesting { DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, ste(x, VALID, DROPPED, true, null), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, x)); - assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "method x()"); - assertDeclareFail("new A().a;", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, x)); + assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "method x()"); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertMethods(); assertActiveKeys(); } diff --git a/langtools/test/jdk/jshell/KullaTesting.java b/langtools/test/jdk/jshell/KullaTesting.java index c2ceeea1e06..0ea4a622499 100644 --- a/langtools/test/jdk/jshell/KullaTesting.java +++ b/langtools/test/jdk/jshell/KullaTesting.java @@ -191,14 +191,14 @@ public class KullaTesting { return key; } - public MethodSnippet assertEvalUnresolvedException(String input, String name, int unresolvedSize, int diagnosticsSize) { + public DeclarationSnippet assertEvalUnresolvedException(String input, String name, int unresolvedSize, int diagnosticsSize) { List events = assertEval(input, null, UnresolvedReferenceException.class, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, null); SnippetEvent ste = events.get(0); - MethodSnippet methodKey = ((UnresolvedReferenceException) ste.exception()).getMethodSnippet(); - assertEquals(methodKey.name(), name, "Given input: " + input + ", checking name"); - assertEquals(getState().unresolvedDependencies(methodKey).size(), unresolvedSize, "Given input: " + input + ", checking unresolved"); - assertEquals(getState().diagnostics(methodKey).size(), diagnosticsSize, "Given input: " + input + ", checking diagnostics"); - return methodKey; + DeclarationSnippet sn = ((UnresolvedReferenceException) ste.exception()).getSnippet(); + assertEquals(sn.name(), name, "Given input: " + input + ", checking name"); + assertEquals(getState().unresolvedDependencies(sn).size(), unresolvedSize, "Given input: " + input + ", checking unresolved"); + assertEquals(getState().diagnostics(sn).size(), diagnosticsSize, "Given input: " + input + ", checking diagnostics"); + return sn; } public Snippet assertKeyMatch(String input, boolean isExecutable, SubKind expectedSubKind, STEInfo mainInfo, STEInfo... updates) { diff --git a/langtools/test/jdk/jshell/ReplaceTest.java b/langtools/test/jdk/jshell/ReplaceTest.java index a26545da577..36b1c505cd4 100644 --- a/langtools/test/jdk/jshell/ReplaceTest.java +++ b/langtools/test/jdk/jshell/ReplaceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -22,7 +22,7 @@ */ /* - * @test + * @test 8080069 * @summary Test of Snippet redefinition and replacement. * @build KullaTesting TestingInputStream * @run testng ReplaceTest @@ -30,6 +30,7 @@ import java.util.Collection; +import java.util.List; import jdk.jshell.Snippet; import jdk.jshell.MethodSnippet; import jdk.jshell.PersistentSnippet; @@ -38,9 +39,11 @@ import jdk.jshell.VarSnippet; import jdk.jshell.DeclarationSnippet; import org.testng.annotations.Test; +import jdk.jshell.SnippetEvent; +import jdk.jshell.UnresolvedReferenceException; +import static org.testng.Assert.assertEquals; import static jdk.jshell.Snippet.Status.*; import static jdk.jshell.Snippet.SubKind.*; -import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @Test @@ -259,7 +262,7 @@ public class ReplaceTest extends KullaTesting { ste(MAIN_SNIPPET, VALID, VALID, true, null), ste(g, VALID, OVERWRITTEN, false, MAIN_SNIPPET), ste(f, VALID, RECOVERABLE_DEFINED, false, MAIN_SNIPPET)); - MethodSnippet exsn = assertEvalUnresolvedException("t();", "f", 0, 1); + DeclarationSnippet exsn = assertEvalUnresolvedException("t();", "f", 0, 1); assertTrue(exsn == f, "Identity must not change"); assertActiveKeys(); } @@ -289,13 +292,95 @@ public class ReplaceTest extends KullaTesting { } public void testForwardVarToClass() { - DeclarationSnippet a = classKey(assertEval("class A { int f() { return g; } }", added(RECOVERABLE_NOT_DEFINED))); - assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "variable g"); + DeclarationSnippet a = classKey(assertEval("class A { int f() { return g; } }", added(RECOVERABLE_DEFINED))); + assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable g"); Snippet g = varKey(assertEval("int g = 10;", "10", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null))); + ste(a, RECOVERABLE_DEFINED, VALID, false, null))); assertEval("new A().f();", "10"); assertEval("double g = 10;", "10.0", null, + DiagCheck.DIAG_OK, + DiagCheck.DIAG_ERROR, + ste(MAIN_SNIPPET, VALID, VALID, true, null), + ste(g, VALID, OVERWRITTEN, false, MAIN_SNIPPET), + ste(a, VALID, RECOVERABLE_DEFINED, false, MAIN_SNIPPET)); + assertUnresolvedDependencies(a, 0); + assertActiveKeys(); + } + + public void testForwardVarToClassGeneric() { + DeclarationSnippet a = classKey(assertEval("class A { final T x; A(T v) { this.x = v; } ; T get() { return x; } int core() { return g; } }", added(RECOVERABLE_DEFINED))); + assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "variable g"); + + List events = assertEval("A as = new A<>(\"hi\");", null, + UnresolvedReferenceException.class, DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, null); + SnippetEvent ste = events.get(0); + Snippet assn = ste.snippet(); + DeclarationSnippet unsn = ((UnresolvedReferenceException) ste.exception()).getSnippet(); + assertEquals(unsn.name(), "A", "Wrong with unresolved"); + assertEquals(getState().unresolvedDependencies(unsn).size(), 1, "Wrong size unresolved"); + assertEquals(getState().diagnostics(unsn).size(), 0, "Expected no diagnostics"); + + Snippet g = varKey(assertEval("int g = 10;", "10", + added(VALID), + ste(a, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET))); + assertEval("A as = new A<>(\"low\");", + ste(MAIN_SNIPPET, VALID, VALID, false, null), + ste(assn, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); + assertEval("as.get();", "\"low\""); + assertUnresolvedDependencies(a, 0); + assertActiveKeys(); + } + + public void testForwardVarToClassExtendsImplements() { + DeclarationSnippet ik = classKey(assertEval("interface I { default int ii() { return 1; } }", added(VALID))); + DeclarationSnippet jk = classKey(assertEval("interface J { default int jj() { return 2; } }", added(VALID))); + DeclarationSnippet ck = classKey(assertEval("class C { int cc() { return 3; } }", added(VALID))); + DeclarationSnippet dk = classKey(assertEval("class D extends C implements I,J { int dd() { return g; } }", added(RECOVERABLE_DEFINED))); + DeclarationSnippet ek = classKey(assertEval("class E extends D { int ee() { return 5; } }", added(VALID))); + assertUnresolvedDependencies1(dk, RECOVERABLE_DEFINED, "variable g"); + assertEvalUnresolvedException("new D();", "D", 1, 0); + assertEvalUnresolvedException("new E();", "D", 1, 0); + VarSnippet g = varKey(assertEval("int g = 10;", "10", + added(VALID), + ste(dk, RECOVERABLE_DEFINED, VALID, false, MAIN_SNIPPET))); + assertEval("E e = new E();"); + assertDrop(g, + ste(g, VALID, DROPPED, true, null), + ste(dk, VALID, RECOVERABLE_DEFINED, false, g)); + assertEvalUnresolvedException("new D();", "D", 1, 0); + assertEvalUnresolvedException("new E();", "D", 1, 0); + assertEval("e.ee();", "5"); + assertEvalUnresolvedException("e.dd();", "D", 1, 0); + assertEval("e.cc();", "3"); + assertEval("e.jj();", "2"); + assertEval("e.ii();", "1"); + assertActiveKeys(); + } + + public void testForwardVarToInterface() { + DeclarationSnippet i = classKey(assertEval("interface I { default int f() { return x; } }", added(RECOVERABLE_DEFINED))); + assertUnresolvedDependencies1(i, RECOVERABLE_DEFINED, "variable x"); + DeclarationSnippet c = classKey(assertEval("class C implements I { int z() { return 2; } }", added(VALID))); + assertEval("C c = new C();"); + assertEval("c.z();", "2"); + assertEvalUnresolvedException("c.f()", "I", 1, 0); + Snippet g = varKey(assertEval("int x = 55;", "55", + added(VALID), + ste(i, RECOVERABLE_DEFINED, VALID, false, null))); + assertEval("c.f();", "55"); + assertUnresolvedDependencies(i, 0); + assertActiveKeys(); + } + + public void testForwardVarToEnum() { + DeclarationSnippet a = classKey(assertEval("enum E { Q, W, E; float ff() { return fff; } }", added(RECOVERABLE_NOT_DEFINED))); + assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "variable fff"); + Snippet g = varKey(assertEval("float fff = 4.5f;", "4.5", + added(VALID), + ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null))); + assertEval("E.Q.ff();", "4.5"); + assertEval("double fff = 3.3;", "3.3", null, DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, ste(MAIN_SNIPPET, VALID, VALID, true, null), @@ -305,20 +390,21 @@ public class ReplaceTest extends KullaTesting { assertActiveKeys(); } - public void testForwardMethodToClass() { - DeclarationSnippet a = classKey(assertEval("class A { int f() { return g(); } }", added(RECOVERABLE_NOT_DEFINED))); - assertUnresolvedDependencies1(a, RECOVERABLE_NOT_DEFINED, "method g()"); + DeclarationSnippet a = classKey(assertEval("class A { int f() { return g(); } }", added(RECOVERABLE_DEFINED))); + assertUnresolvedDependencies1(a, RECOVERABLE_DEFINED, "method g()"); + assertEval("A foo() { return null; }"); + assertEvalUnresolvedException("new A();", "A", 1, 0); Snippet g = methodKey(assertEval("int g() { return 10; }", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null))); + ste(a, RECOVERABLE_DEFINED, VALID, false, null))); assertEval("new A().f();", "10"); assertEval("double g() { return 10; }", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, ste(MAIN_SNIPPET, VALID, VALID, true, null), ste(g, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET)); + ste(a, VALID, RECOVERABLE_DEFINED, false, MAIN_SNIPPET)); assertUnresolvedDependencies(a, 0); assertActiveKeys(); } @@ -336,8 +422,8 @@ public class ReplaceTest extends KullaTesting { DiagCheck.DIAG_ERROR, ste(MAIN_SNIPPET, VALID, VALID, true, null), ste(b, VALID, OVERWRITTEN, false, MAIN_SNIPPET), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET)); - assertDeclareFail("new A().b;", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, true, MAIN_SNIPPET)); + assertEvalUnresolvedException("new A().b;", "A", 0, 1); assertActiveKeys(); } @@ -503,42 +589,42 @@ public class ReplaceTest extends KullaTesting { public void testForwardSingleImportMethodToClass1() { PersistentSnippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.String.format;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, false, null)); assertEval("new A().s;", "\"10\""); PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, MAIN_SNIPPET))); - assertDeclareFail("new A().s;", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, MAIN_SNIPPET))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(format, ste(format, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, format)); + ste(a, RECOVERABLE_DEFINED, VALID, false, format)); } public void testForwardSingleImportMethodToClass2() { PersistentSnippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.String.format;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, false, null)); assertEval("new A().s();", "\"10\""); PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A().s();", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(format, ste(format, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, format)); + ste(a, RECOVERABLE_DEFINED, VALID, false, format)); } public void testForwardSingleImportClassToClass1() { @@ -589,42 +675,44 @@ public class ReplaceTest extends KullaTesting { public void testForwardImportOnDemandMethodToClass1() { PersistentSnippet a = classKey(assertEval("class A { String s = format(\"%d\", 10); }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.String.*;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); - assertEval("new A().s;", "\"10\""); + ste(a, RECOVERABLE_DEFINED, VALID, false, null)); + assertEval("A x = new A();"); + assertEval("x.s;", "\"10\""); PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A().s;", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(format, ste(format, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, format)); + ste(a, RECOVERABLE_DEFINED, VALID, false, format)); + assertEval("x.s;", "\"10\""); } public void testForwardImportOnDemandMethodToClass2() { PersistentSnippet a = classKey(assertEval("class A { String s() { return format(\"%d\", 10); } }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.String.*;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, false, null)); assertEval("new A().s();", "\"10\""); PersistentSnippet format = methodKey(assertEval("void format(String s, int d) { }", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A().s();", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(format, ste(format, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, format)); + ste(a, RECOVERABLE_DEFINED, VALID, false, format)); } public void testForwardImportOnDemandClassToClass1() { @@ -673,86 +761,87 @@ public class ReplaceTest extends KullaTesting { public void testForwardSingleImportFieldToClass1() { PersistentSnippet a = classKey(assertEval("class A { static double pi() { return PI; } }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.Math.PI;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, false, null)); assertEval("Math.abs(A.pi() - 3.1415) < 0.001;", "true"); PersistentSnippet list = varKey(assertEval("String PI;", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(list, ste(list, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list)); + ste(a, RECOVERABLE_DEFINED, VALID, false, list)); } public void testForwardSingleImportFieldToClass2() { PersistentSnippet a = classKey(assertEval("class A { static double pi = PI; }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.Math.PI;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, true, null)); assertEval("Math.abs(A.pi - 3.1415) < 0.001;", "true"); PersistentSnippet list = varKey(assertEval("String PI;", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, true, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(list, ste(list, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list)); + ste(a, RECOVERABLE_DEFINED, VALID, true, list)); } public void testForwardImportOnDemandFieldToClass1() { PersistentSnippet a = classKey(assertEval("class A { static double pi() { return PI; } }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.Math.*;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, false, null)); assertEval("Math.abs(A.pi() - 3.1415) < 0.001;", "true"); PersistentSnippet list = varKey(assertEval("String PI;", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, false, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(list, ste(list, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list)); + ste(a, RECOVERABLE_DEFINED, VALID, false, list)); } public void testForwardImportOnDemandFieldToClass2() { PersistentSnippet a = classKey(assertEval("class A { static double pi = PI; }", - added(RECOVERABLE_NOT_DEFINED))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + added(RECOVERABLE_DEFINED))); + assertEvalUnresolvedException("new A();", "A", 1, 0); assertEval("import static java.lang.Math.*;", added(VALID), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, null)); + ste(a, RECOVERABLE_DEFINED, VALID, true, null)); assertEval("Math.abs(A.pi - 3.1415) < 0.001;", "true"); PersistentSnippet list = varKey(assertEval("String PI;", DiagCheck.DIAG_OK, DiagCheck.DIAG_ERROR, added(VALID), - ste(a, VALID, RECOVERABLE_NOT_DEFINED, true, null))); - assertDeclareFail("new A();", "compiler.err.cant.resolve.location"); + ste(a, VALID, RECOVERABLE_DEFINED, true, null))); + assertEvalUnresolvedException("new A();", "A", 0, 1); assertActiveKeys(); assertDrop(list, ste(list, VALID, DROPPED, true, null), - ste(a, RECOVERABLE_NOT_DEFINED, VALID, true, list)); + ste(a, RECOVERABLE_DEFINED, VALID, true, list)); + assertEval("Math.abs(A.pi - 3.1415) < 0.001;", "true"); } public void testReplaceCausesMethodReferenceError() { From 0bca52a90883fa850b5e0018471ef317d3df387b Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Wed, 24 Feb 2016 15:31:36 -0800 Subject: [PATCH 070/183] 8149139: [javadoc] Modify Content to accept CharSequence Reviewed-by: jjg --- .../html/AbstractExecutableMemberWriter.java | 10 ++-- .../formats/html/AbstractMemberWriter.java | 24 +------- .../doclets/formats/html/ClassWriterImpl.java | 7 +-- .../html/ConstantsSummaryWriterImpl.java | 4 +- .../formats/html/HtmlDocletWriter.java | 60 +++++++++---------- .../doclets/formats/html/LinkInfoImpl.java | 2 +- .../formats/html/MethodWriterImpl.java | 5 +- .../formats/html/PackageIndexFrameWriter.java | 2 +- .../formats/html/PropertyWriterImpl.java | 2 +- .../formats/html/TagletWriterImpl.java | 3 +- .../doclets/formats/html/markup/Comment.java | 5 +- .../formats/html/markup/ContentBuilder.java | 6 +- .../doclets/formats/html/markup/DocType.java | 5 +- .../formats/html/markup/HtmlDocument.java | 5 +- .../doclets/formats/html/markup/HtmlTree.java | 3 +- .../formats/html/markup/HtmlWriter.java | 2 +- .../doclets/formats/html/markup/RawHtml.java | 11 ++-- .../formats/html/markup/StringContent.java | 8 +-- .../internal/doclets/toolkit/Content.java | 4 +- .../internal/doclets/toolkit/util/Utils.java | 6 +- 20 files changed, 79 insertions(+), 95 deletions(-) diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java index d82da4653cd..44977bfb71a 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java @@ -104,11 +104,11 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite sb.append(utils.getFullyQualifiedName(member)); if (!utils.isConstructor(member)) { sb.append("."); - sb.append(member.getSimpleName().toString()); + sb.append(member.getSimpleName()); } sb.append(utils.flatSignature((ExecutableElement) member)); - return writer.getDocLink(MEMBER, member, sb.toString()); + return writer.getDocLink(MEMBER, member, sb); } /** @@ -204,7 +204,7 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite htmltree.addContent("("); String sep = ""; List parameters = member.getParameters(); - String indent = makeSpace(indentSize + 1); + CharSequence indent = makeSpace(indentSize + 1); TypeMirror rcvrType = member.getReceiverType(); if (includeAnnotations && rcvrType != null && utils.isAnnotated(rcvrType)) { List annotationMirrors = rcvrType.getAnnotationMirrors(); @@ -260,7 +260,7 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite protected void addExceptions(ExecutableElement member, Content htmltree, int indentSize) { List exceptions = member.getThrownTypes(); if (!exceptions.isEmpty()) { - String indent = makeSpace(indentSize + 1 - 7); + CharSequence indent = makeSpace(indentSize + 1 - 7); htmltree.addContent(DocletConstants.NL); htmltree.addContent(indent); htmltree.addContent("throws "); @@ -336,7 +336,7 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite @Override @DefinedBy(Api.LANGUAGE_MODEL) protected Boolean defaultAction(TypeMirror e, Void p) { - buf.append(e.toString()); + buf.append(e); return foundTypeVariable; } }; diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java index aa04f515ea1..50f4c099807 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java @@ -223,26 +223,6 @@ public abstract class AbstractMemberWriter { htmltree.addContent(name); } - protected String typeString(Element member) { - return new SimpleElementVisitor9() { - - @Override @DefinedBy(Api.LANGUAGE_MODEL) - public String visitExecutable(ExecutableElement e, Void p) { - return utils.isMethod(e) ? e.getReturnType().toString() : ""; - } - - @Override @DefinedBy(Api.LANGUAGE_MODEL) - public String visitVariable(VariableElement e, Void p) { - return e.toString(); - } - - @Override @DefinedBy(Api.LANGUAGE_MODEL) - protected String defaultAction(Element e, Void p) { - return ""; - } - }.visit(member); - } - /** * Add the modifier for the member. The modifiers are ordered as specified * by The Java Language Specification. @@ -282,7 +262,7 @@ public abstract class AbstractMemberWriter { } } - protected String makeSpace(int len) { + protected CharSequence makeSpace(int len) { if (len <= 0) { return ""; } @@ -290,7 +270,7 @@ public abstract class AbstractMemberWriter { for (int i = 0; i < len; i++) { sb.append(' '); } - return sb.toString(); + return sb; } /** diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java index 9356fb7f3c2..17efe9c9c52 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java @@ -199,8 +199,7 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite Content classPackageLabel = HtmlTree.SPAN(HtmlStyle.packageLabelInClass, packageLabel); Content pkgNameDiv = HtmlTree.DIV(HtmlStyle.subTitle, classPackageLabel); pkgNameDiv.addContent(getSpace()); - Content pkgNameContent = getPackageLink(pkg, - new StringContent(pkg.getQualifiedName().toString())); + Content pkgNameContent = getPackageLink(pkg, new StringContent(pkg.getQualifiedName())); pkgNameDiv.addContent(pkgNameContent); div.addContent(pkgNameDiv); } @@ -395,10 +394,10 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite new LinkInfoImpl(configuration, LinkInfoImpl.Kind.TREE, typeElement)); if (configuration.shouldExcludeQualifier(utils.containingPackage(typeElement).toString())) { - li.addContent(utils.asTypeElement(type).getSimpleName().toString()); + li.addContent(utils.asTypeElement(type).getSimpleName()); li.addContent(typeParameters); } else { - li.addContent(utils.asTypeElement(type).getQualifiedName().toString()); + li.addContent(utils.asTypeElement(type).getQualifiedName()); li.addContent(typeParameters); } } else { diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java index 2b993595998..70f4a0fdd5a 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java @@ -244,7 +244,7 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter implements Cons PackageElement enclosingPackage = utils.containingPackage(typeElement); if (!enclosingPackage.isUnnamed()) { Content cb = new ContentBuilder(); - cb.addContent(enclosingPackage.getQualifiedName().toString()); + cb.addContent(enclosingPackage.getQualifiedName()); cb.addContent("."); cb.addContent(classlink); return getClassName(cb); @@ -332,7 +332,7 @@ public class ConstantsSummaryWriterImpl extends HtmlDocletWriter implements Cons */ private Content getNameColumn(VariableElement member) { Content nameContent = getDocLink(LinkInfoImpl.Kind.CONSTANT_SUMMARY, - member, member.getSimpleName().toString(), false); + member, member.getSimpleName(), false); Content code = HtmlTree.CODE(nameContent); return HtmlTree.TD(code); } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index c5daf0fa50b..294bc605891 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -166,6 +166,8 @@ public class HtmlDocletWriter extends HtmlDocWriter { HtmlTree fixedNavDiv = new HtmlTree(HtmlTag.DIV); + final static Pattern IMPROPER_HTML_CHARS = Pattern.compile(".*[&<>].*"); + /** * Constructor to construct the HtmlStandardWriter object. * @@ -945,7 +947,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { public Content getPackageName(PackageElement packageElement) { return packageElement == null || packageElement.isUnnamed() ? defaultPackageLabel - : getPackageLabel(packageElement.getQualifiedName().toString()); + : getPackageLabel(packageElement.getQualifiedName()); } /** @@ -954,7 +956,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { * @param packageName the package name * @return the package name content */ - public Content getPackageLabel(String packageName) { + public Content getPackageLabel(CharSequence packageName) { return new StringContent(packageName); } @@ -1038,7 +1040,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { * @param label the label for the link. * @return a content tree for the package link. */ - public Content getPackageLink(PackageElement packageElement, String label) { + public Content getPackageLink(PackageElement packageElement, CharSequence label) { return getPackageLink(packageElement, new StringContent(label)); } @@ -1081,7 +1083,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { public Content interfaceName(TypeElement typeElement, boolean qual) { Content name = new StringContent((qual) - ? typeElement.getQualifiedName().toString() + ? typeElement.getQualifiedName() : utils.getSimpleName(typeElement)); return (utils.isInterface(typeElement)) ? HtmlTree.SPAN(HtmlStyle.interfaceName, name) : name; } @@ -1279,7 +1281,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { * @param label the label for the link * @return a content tree for the element link */ - public Content getDocLink(LinkInfoImpl.Kind context, Element element, String label) { + public Content getDocLink(LinkInfoImpl.Kind context, Element element, CharSequence label) { return getDocLink(context, utils.getEnclosingTypeElement(element), element, new StringContent(label)); } @@ -1293,7 +1295,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { * @param strong true if the link should be strong. * @return the link for the given member. */ - public Content getDocLink(LinkInfoImpl.Kind context, Element element, String label, + public Content getDocLink(LinkInfoImpl.Kind context, Element element, CharSequence label, boolean strong) { return getDocLink(context, utils.getEnclosingTypeElement(element), element, label, strong); } @@ -1311,7 +1313,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { * @return the link for the given member. */ public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, - String label, boolean strong) { + CharSequence label, boolean strong) { return getDocLink(context, typeElement, element, label, strong, false); } @@ -1334,13 +1336,14 @@ public class HtmlDocletWriter extends HtmlDocWriter { * @return the link for the given member. */ public Content getDocLink(LinkInfoImpl.Kind context, TypeElement typeElement, Element element, - String label, boolean strong, boolean isProperty) { + CharSequence label, boolean strong, boolean isProperty) { return getDocLink(context, typeElement, element, new StringContent(check(label)), strong, isProperty); } - String check(String s) { - if (s.matches(".*[&<>].*")) { - throw new IllegalArgumentException(s); + CharSequence check(CharSequence s) { + Matcher m = IMPROPER_HTML_CHARS.matcher(s); + if (m.matches()) { + throw new IllegalArgumentException(s.toString()); } return s; } @@ -1426,7 +1429,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { CommentHelper ch = utils.getCommentHelper(element); String tagName = ch.getTagName(see); - String seetext = replaceDocRootDir(utils.normalizeNewlines(ch.getText(see))); + String seetext = replaceDocRootDir(utils.normalizeNewlines(ch.getText(see)).toString()); // Check if @see is an href or "string" if (seetext.startsWith("<") || seetext.startsWith("\"")) { return new RawHtml(seetext); @@ -1452,7 +1455,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { //@see is referencing an included package if (label.isEmpty()) label = plainOrCode(isLinkPlain, - new StringContent(refPackage.getQualifiedName().toString())); + new StringContent(refPackage.getQualifiedName())); return getPackageLink(refPackage, label); } else { // @see is not referencing an included class or package. Check for cross links. @@ -1695,7 +1698,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { final Content result = new ContentBuilder() { @Override - public void addContent(String text) { + public void addContent(CharSequence text) { super.addContent(utils.normalizeNewlines(text)); } }; @@ -1741,7 +1744,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { public Boolean visitAttribute(AttributeTree node, Content c) { StringBuilder sb = new StringBuilder(SPACER).append(node.getName()); if (node.getValueKind() == ValueKind.EMPTY) { - result.addContent(sb.toString()); + result.addContent(sb); return false; } sb.append("="); @@ -1758,7 +1761,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { break; } sb.append(quote); - result.addContent(sb.toString()); + result.addContent(sb); Content docRootContent = new ContentBuilder(); for (DocTree dt : node.getValue()) { @@ -1767,16 +1770,15 @@ public class HtmlDocletWriter extends HtmlDocWriter { if (text.startsWith("/..") && !configuration.docrootparent.isEmpty()) { result.addContent(configuration.docrootparent); docRootContent = new ContentBuilder(); - text = textCleanup(text.substring(3), isLast(node)); + result.addContent(textCleanup(text.substring(3), isLast(node))); } else { if (!docRootContent.isEmpty()) { docRootContent = copyDocRootContent(docRootContent); } else { text = redirectRelativeLinks(element, (TextTree) dt); } - text = textCleanup(text, isLast(node)); + result.addContent(textCleanup(text, isLast(node))); } - result.addContent(text); } else { docRootContent = copyDocRootContent(docRootContent); dt.accept(this, docRootContent); @@ -1889,8 +1891,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { @Override @DefinedBy(Api.COMPILER_TREE) public Boolean visitStartElement(StartElementTree node, Content c) { String text = "<" + node.getName(); - text = utils.normalizeNewlines(text); - RawHtml rawHtml = new RawHtml(text); + RawHtml rawHtml = new RawHtml(utils.normalizeNewlines(text)); result.addContent(rawHtml); for (DocTree dt : node.getAttributes()) { @@ -1900,11 +1901,11 @@ public class HtmlDocletWriter extends HtmlDocWriter { return false; } - private String textCleanup(String text, boolean isLast) { + private CharSequence textCleanup(String text, boolean isLast) { return textCleanup(text, isLast, false); } - private String textCleanup(String text, boolean isLast, boolean trimLeader) { + private CharSequence textCleanup(String text, boolean isLast, boolean trimLeader) { if (trimLeader) { text = removeLeadingWhitespace(text); } @@ -1912,16 +1913,14 @@ public class HtmlDocletWriter extends HtmlDocWriter { text = removeTrailingWhitespace(text); } text = utils.replaceTabs(text); - text = utils.normalizeNewlines(text); - return text; + return utils.normalizeNewlines(text); } @Override @DefinedBy(Api.COMPILER_TREE) public Boolean visitText(TextTree node, Content c) { String text = node.getBody(); - text = textCleanup(text, isLast(node), commentRemoved); + result.addContent(new RawHtml(textCleanup(text, isLast(node), commentRemoved))); commentRemoved = false; - result.addContent(new RawHtml(text)); return false; } @@ -2358,7 +2357,8 @@ public class HtmlDocletWriter extends HtmlDocWriter { private void addAnnotations(TypeElement annotationDoc, LinkInfoImpl linkInfo, ContentBuilder annotation, Mapmap, int indent, boolean linkBreak) { - linkInfo.label = new StringContent("@" + annotationDoc.getSimpleName().toString()); + linkInfo.label = new StringContent("@"); + linkInfo.label.addContent(annotationDoc.getSimpleName()); annotation.addContent(getLink(linkInfo)); if (!map.isEmpty()) { annotation.addContent("("); @@ -2372,7 +2372,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { annotation.addContent(","); if (linkBreak) { annotation.addContent(DocletConstants.NL); - int spaces = annotationDoc.getSimpleName().toString().length() + 2; + int spaces = annotationDoc.getSimpleName().length() + 2; for (int k = 0; k < (spaces + indent); k++) { annotation.addContent(" "); } @@ -2496,7 +2496,7 @@ public class HtmlDocletWriter extends HtmlDocWriter { @Override @DefinedBy(Api.LANGUAGE_MODEL) public Content visitEnumConstant(VariableElement c, Void p) { return getDocLink(LinkInfoImpl.Kind.ANNOTATION, - c, c.getSimpleName().toString(), false); + c, c.getSimpleName(), false); } @Override @DefinedBy(Api.LANGUAGE_MODEL) public Content visitArray(List vals, Void p) { diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkInfoImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkInfoImpl.java index 01cd9508a1a..30801a6bbc9 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkInfoImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/LinkInfoImpl.java @@ -294,7 +294,7 @@ public class LinkInfoImpl extends LinkInfo { * Set the label for the link. * @param label plain-text label for the link */ - public LinkInfoImpl label(String label) { + public LinkInfoImpl label(CharSequence label) { this.label = new StringContent(label); return this; } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java index 40b00cdd1fd..68648d4aaaa 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java @@ -356,11 +356,10 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter Content overriddenTypeLink = writer.getLink(new LinkInfoImpl(writer.configuration, context, overriddenType)); Content codeOverridenTypeLink = HtmlTree.CODE(overriddenTypeLink); - String name = method.getSimpleName().toString(); Content methlink = writer.getLink( new LinkInfoImpl(writer.configuration, LinkInfoImpl.Kind.MEMBER, holder) - .where(writer.getName(writer.getAnchor(method))).label(name)); + .where(writer.getName(writer.getAnchor(method))).label(method.getSimpleName())); Content codeMethLink = HtmlTree.CODE(methlink); Content dd = HtmlTree.DD(codeMethLink); dd.addContent(writer.getSpace()); @@ -395,7 +394,7 @@ public class MethodWriterImpl extends AbstractExecutableMemberWriter dl.addContent(dt); Content methlink = writer.getDocLink( LinkInfoImpl.Kind.MEMBER, implementedMeth, - implementedMeth.getSimpleName().toString(), false); + implementedMeth.getSimpleName(), false); Content codeMethLink = HtmlTree.CODE(methlink); Content dd = HtmlTree.DD(codeMethLink); dd.addContent(writer.getSpace()); diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexFrameWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexFrameWriter.java index 064a93ce9d2..94170a334fb 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexFrameWriter.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexFrameWriter.java @@ -123,7 +123,7 @@ public class PackageIndexFrameWriter extends AbstractPackageIndexWriter { packageLinkContent = getHyperLink(DocPaths.PACKAGE_FRAME, packageLabel, "", "packageFrame"); } else { - packageLabel = getPackageLabel(pe.getQualifiedName().toString()); + packageLabel = getPackageLabel(pe.getQualifiedName()); packageLinkContent = getHyperLink(pathString(pe, DocPaths.PACKAGE_FRAME), packageLabel, "", "packageFrame"); diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java index 3a1eebc23cf..9b7ca5da8ed 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java @@ -158,7 +158,7 @@ public class PropertyWriterImpl extends AbstractMemberWriter writer.getDocLink(LinkInfoImpl.Kind.PROPERTY_COPY, holder, property, utils.isIncluded(holder) - ? holder.toString() : utils.getFullyQualifiedName(holder), + ? holder.getSimpleName() : holder.getQualifiedName(), false); Content codeLink = HtmlTree.CODE(link); Content descfrmLabel = HtmlTree.SPAN(HtmlStyle.descfrmTypeLabel, diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java index 1ae644233b2..80a4cccf532 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java @@ -91,8 +91,7 @@ public class TagletWriterImpl extends TagletWriter { */ protected Content codeTagOutput(Element element, DocTree tag) { CommentHelper ch = utils.getCommentHelper(element); - String str = utils.normalizeNewlines(ch.getText(tag)); - StringContent content = new StringContent(str); + StringContent content = new StringContent(utils.normalizeNewlines(ch.getText(tag))); Content result = HtmlTree.CODE(content); return result; } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java index 0adfc088106..32c5cc6c5b3 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Comment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, 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 @@ -75,7 +75,8 @@ public class Comment extends Content { * DocletAbortException because it * is not supported. */ - public void addContent(String stringContent) { + @Override + public void addContent(CharSequence stringContent) { throw new DocletAbortException("not supported"); } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java index 64ceef82473..e4a9265cbbd 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/ContentBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, 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 @@ -50,8 +50,8 @@ public class ContentBuilder extends Content { } @Override - public void addContent(String text) { - if (text.isEmpty()) + public void addContent(CharSequence text) { + if (text.length() == 0) return; ensureMutableContents(); Content c = contents.isEmpty() ? null : contents.get(contents.size() - 1); diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java index 469ee40743f..cd6739d3f1f 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/DocType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, 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 @@ -89,7 +89,8 @@ public class DocType extends Content { * DocletAbortException because it * is not supported. */ - public void addContent(String stringContent) { + @Override + public void addContent(CharSequence stringContent) { throw new DocletAbortException("not supported"); } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java index 8f995c7c772..73da0086ab1 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlDocument.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, 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 @@ -90,7 +90,8 @@ public class HtmlDocument extends Content { * DocletAbortException because it * is not supported. */ - public void addContent(String stringContent) { + @Override + public void addContent(CharSequence stringContent) { throw new DocletAbortException("not supported"); } diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java index 93b9071dcf7..a3a40f4391e 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlTree.java @@ -132,7 +132,8 @@ public class HtmlTree extends Content { * * @param stringContent string content that needs to be added */ - public void addContent(String stringContent) { + @Override + public void addContent(CharSequence stringContent) { if (!content.isEmpty()) { Content lastContent = content.get(content.size() - 1); if (lastContent instanceof StringContent) diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlWriter.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlWriter.java index 88c93108672..dce9fd720a7 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlWriter.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlWriter.java @@ -475,7 +475,7 @@ public class HtmlWriter { addStyles(HtmlStyle.rowColor, vars); addStyles(HtmlStyle.tableTab, vars); addStyles(HtmlStyle.activeTableTab, vars); - script.addContent(new RawHtml(vars.toString())); + script.addContent(new RawHtml(vars)); } /** diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java index fe425dd743a..ca621a4c75a 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/RawHtml.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, 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 @@ -53,8 +53,8 @@ public class RawHtml extends Content { * * @param rawHtml raw HTML text to be added */ - public RawHtml(String rawHtml) { - rawHtmlContent = nullCheck(rawHtml); + public RawHtml(CharSequence rawHtml) { + rawHtmlContent = rawHtml.toString(); } /** @@ -77,7 +77,8 @@ public class RawHtml extends Content { * DocletAbortException because it * is not supported. */ - public void addContent(String stringContent) { + @Override + public void addContent(CharSequence stringContent) { throw new DocletAbortException("not supported"); } @@ -103,7 +104,7 @@ public class RawHtml extends Content { return charCount(rawHtmlContent); } - static int charCount(String htmlText) { + static int charCount(CharSequence htmlText) { State state = State.TEXT; int count = 0; for (int i = 0; i < htmlText.length(); i++) { diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/StringContent.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/StringContent.java index 6b7c7dde2ed..cececf6b991 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/StringContent.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/StringContent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, 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 @@ -58,7 +58,7 @@ public class StringContent extends Content { * * @param initialContent initial content for the object */ - public StringContent(String initialContent) { + public StringContent(CharSequence initialContent) { stringContent = new StringBuilder(); appendChars(initialContent); } @@ -83,7 +83,7 @@ public class StringContent extends Content { * @param strContent string content to be added */ @Override - public void addContent(String strContent) { + public void addContent(CharSequence strContent) { appendChars(strContent); } @@ -118,7 +118,7 @@ public class StringContent extends Content { return s.endsWith(DocletConstants.NL); } - private void appendChars(String s) { + private void appendChars(CharSequence s) { for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); switch (ch) { diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java index 3d2e664a3e0..7efd4250504 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Content.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, 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 @@ -74,7 +74,7 @@ public abstract class Content { * * @param stringContent the string content to be added */ - public abstract void addContent(String stringContent); + public abstract void addContent(CharSequence stringContent); /** * Writes content to a writer. diff --git a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java index 5914a2e6013..fa2c90f1efe 100644 --- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java +++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java @@ -1356,7 +1356,7 @@ public class Utils { return result.toString(); } - public String normalizeNewlines(String text) { + public CharSequence normalizeNewlines(CharSequence text) { StringBuilder sb = new StringBuilder(); final int textLength = text.length(); final String NL = DocletConstants.NL; @@ -1379,7 +1379,7 @@ public class Utils { } } sb.append(text, pos, textLength); - return sb.toString(); + return sb; } /** @@ -1746,6 +1746,8 @@ public class Utils { * A generic utility which returns the fully qualified names of an entity, * if the entity is not qualifiable then its enclosing entity, it is upto * the caller to add the elements name as required. + * @param e the element to get FQN for. + * @return the name */ public String getFullyQualifiedName(Element e) { return getFullyQualifiedName(e, true); From 42867443a4bd204e6adb92ddea0fb62a795d3ee7 Mon Sep 17 00:00:00 2001 From: Ajit Ghaisas Date: Thu, 25 Feb 2016 10:22:22 +0530 Subject: [PATCH 071/183] 8020039: SynthTableHeaderUI refers to possibly null parameter in cell renderer Reviewed-by: rchamyal, serb --- .../com/apple/laf/AquaTableHeaderUI.java | 15 +++--- .../swing/plaf/synth/SynthTableHeaderUI.java | 3 +- .../TableHeaderRendererExceptionTest.java | 53 +++++++++++++++++++ 3 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 jdk/test/javax/swing/JTableHeader/8020039/TableHeaderRendererExceptionTest.java diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java index 2dec5c895eb..35b87aac27e 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java @@ -128,14 +128,17 @@ public class AquaTableHeaderUI extends BasicTableHeaderUI { // Modify the table "border" to draw smaller, and with the titles in the right position // and sort indicators, just like an NSSave/Open panel. final AquaTableHeaderBorder cellBorder = AquaTableHeaderBorder.getListHeaderBorder(); - final boolean thisColumnSelected = localTable.getColumnModel().getColumn(column).getModelIndex() == sortColumn; + cellBorder.setSortOrder(AquaTableHeaderBorder.SORT_NONE); - cellBorder.setSelected(thisColumnSelected); - if (thisColumnSelected) { - cellBorder.setSortOrder(sortOrder); - } else { - cellBorder.setSortOrder(AquaTableHeaderBorder.SORT_NONE); + if (localTable != null) { + final boolean thisColumnSelected = localTable.getColumnModel().getColumn(column).getModelIndex() == sortColumn; + + cellBorder.setSelected(thisColumnSelected); + if (thisColumnSelected) { + cellBorder.setSortOrder(sortOrder); + } } + setBorder(cellBorder); return this; } diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableHeaderUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableHeaderUI.java index 904172fa049..16272ffa819 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableHeaderUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableHeaderUI.java @@ -230,9 +230,10 @@ public class SynthTableHeaderUI extends BasicTableHeaderUI boolean hasRollover = (column == getRolloverColumn()); if (isSelected || hasRollover || hasFocus) { + boolean enabled = (table == null)? true : table.isEnabled(); SynthLookAndFeel.setSelectedUI((SynthLabelUI)SynthLookAndFeel. getUIOfType(getUI(), SynthLabelUI.class), - isSelected, hasFocus, table.isEnabled(), + isSelected, hasFocus, enabled, hasRollover); } else { SynthLookAndFeel.resetSelectedUI(); diff --git a/jdk/test/javax/swing/JTableHeader/8020039/TableHeaderRendererExceptionTest.java b/jdk/test/javax/swing/JTableHeader/8020039/TableHeaderRendererExceptionTest.java new file mode 100644 index 00000000000..54ac5fd2619 --- /dev/null +++ b/jdk/test/javax/swing/JTableHeader/8020039/TableHeaderRendererExceptionTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, 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 javax.swing.UIManager; +import javax.swing.table.JTableHeader; + +/** + * @test + * @summary Tests whether getTableCellRendererComponent() method handles + * null table parameter + * @bug 8020039 + * @run main TableHeaderRendererExceptionTest + */ +public class TableHeaderRendererExceptionTest { + + public static void main(String[] args) throws Throwable { + //Execute test for all supported look and feels + UIManager.LookAndFeelInfo[] lookAndFeelArray + = UIManager.getInstalledLookAndFeels(); + + for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) { + String lookAndFeelString = lookAndFeelItem.getClassName(); + + UIManager.setLookAndFeel(lookAndFeelString); + + // Test getTableCellRendererComponent method by passing null table + JTableHeader header = new JTableHeader(); + + header.getDefaultRenderer().getTableCellRendererComponent(null, + " test ", true, true, -1, 0); + } + } +} From a9a432a1a1774056ff85e01d34fd1e4c398a5ce2 Mon Sep 17 00:00:00 2001 From: Shafi Ahmad Date: Thu, 25 Feb 2016 11:27:13 +0530 Subject: [PATCH 072/183] 8150002: Check for the validity of oop before printing it in verify_remembered_set Adding missing check for valid oop. Reviewed-by: dcubed --- hotspot/src/share/vm/gc/g1/heapRegion.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.cpp b/hotspot/src/share/vm/gc/g1/heapRegion.cpp index 1c332adcdf1..42cb7d5928a 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp @@ -781,7 +781,9 @@ public: ResourceMark rm; _containing_obj->print_on(log.error_stream()); log.error("points to obj " PTR_FORMAT " in region " HR_FORMAT, p2i(obj), HR_FORMAT_PARAMS(to)); - obj->print_on(log.error_stream()); + if (obj->is_oop()) { + obj->print_on(log.error_stream()); + } log.error("Obj head CTE = %d, field CTE = %d.", cv_obj, cv_field); log.error("----------"); _failures = true; From be1f49a6fdc3252f91763eb701b64d4c4b457ca5 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Thu, 25 Feb 2016 10:43:04 +0100 Subject: [PATCH 073/183] 8148159: [TESTBUG] TestCompilerDirectivesCompatibility tests fails on non-tiered server VMs Add whitebox for checking available compilers Reviewed-by: kvn --- test/lib/sun/hotspot/WhiteBox.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/sun/hotspot/WhiteBox.java b/test/lib/sun/hotspot/WhiteBox.java index 9964831c3c9..668d2f00c1a 100644 --- a/test/lib/sun/hotspot/WhiteBox.java +++ b/test/lib/sun/hotspot/WhiteBox.java @@ -207,7 +207,7 @@ public class WhiteBox { // Compiler public native int matchesMethod(Executable method, String pattern); public native int matchesInline(Executable method, String pattern); - public native boolean shouldPrintAssembly(Executable method); + public native boolean shouldPrintAssembly(Executable method, int comp_level); public native int deoptimizeFrames(boolean makeNotEntrant); public native void deoptimizeAll(); From 167ce92545929e1afd69eb29306cbbf40d04ecb5 Mon Sep 17 00:00:00 2001 From: Mikael Gerdin Date: Thu, 25 Feb 2016 11:20:03 +0100 Subject: [PATCH 074/183] 8150390: Move rs length sampling data to the sampling thread Reviewed-by: drwhite, jwilhelm --- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 7 +-- .../src/share/vm/gc/g1/g1CollectedHeap.hpp | 3 +- .../src/share/vm/gc/g1/g1CollectorPolicy.cpp | 3 +- .../src/share/vm/gc/g1/g1CollectorPolicy.hpp | 2 +- .../vm/gc/g1/g1YoungRemSetSamplingThread.cpp | 29 +++++++++--- hotspot/src/share/vm/gc/g1/youngList.cpp | 46 ++----------------- hotspot/src/share/vm/gc/g1/youngList.hpp | 16 +------ 7 files changed, 32 insertions(+), 74 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index f241d749045..be30e88c541 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -1400,7 +1400,6 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, JavaThread::dirty_card_queue_set().abandon_logs(); assert(dirty_card_queue_set().completed_buffers_num() == 0, "DCQS should be empty"); - _young_list->reset_sampled_info(); // At this point there should be no regions in the // entire heap tagged as young. assert(check_young_list_empty(true /* check_heap */), @@ -3390,8 +3389,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { clear_cset_fast_test(); - _young_list->reset_sampled_info(); - // Don't check the whole heap at this point as the // GC alloc regions from this pause have been tagged // as survivors and moved on to the survivor list. @@ -5188,8 +5185,8 @@ public: bool success() { return _success; } }; -bool G1CollectedHeap::check_young_list_empty(bool check_heap, bool check_sample) { - bool ret = _young_list->check_list_empty(check_sample); +bool G1CollectedHeap::check_young_list_empty(bool check_heap) { + bool ret = _young_list->check_list_empty(); if (check_heap) { NoYoungRegionsClosure closure; diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index 3d8badc27bb..a62d1c6a8ed 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -1333,8 +1333,7 @@ public: return _young_list->check_list_well_formed(); } - bool check_young_list_empty(bool check_heap, - bool check_sample = true); + bool check_young_list_empty(bool check_heap); // *** Stuff related to concurrent marking. It's not clear to me that so // many of these need to be public. diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index 93b2cce3dd1..f14e360ce44 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -787,10 +787,9 @@ double G1CollectorPolicy::predict_survivor_regions_evac_time() const { return survivor_regions_evac_time; } -void G1CollectorPolicy::revise_young_list_target_length_if_necessary() { +void G1CollectorPolicy::revise_young_list_target_length_if_necessary(size_t rs_lengths) { guarantee( adaptive_young_list_length(), "should not call this otherwise" ); - size_t rs_lengths = _g1->young_list()->sampled_rs_lengths(); if (rs_lengths > _rs_lengths_prediction) { // add 10% to avoid having to recalculate often size_t rs_lengths_prediction = rs_lengths * 1100 / 1000; diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp index fbdc47742cf..6db53e64119 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp @@ -471,7 +471,7 @@ public: // Check the current value of the young list RSet lengths and // compare it against the last prediction. If the current value is // higher, recalculate the young list target length prediction. - void revise_young_list_target_length_if_necessary(); + void revise_young_list_target_length_if_necessary(size_t rs_lengths); // This should be called after the heap is resized. void record_new_heap_size(uint new_number_of_regions); diff --git a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp index b511b04617f..8c8d216478c 100644 --- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp +++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp @@ -26,6 +26,8 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1YoungRemSetSamplingThread.hpp" +#include "gc/g1/heapRegion.inline.hpp" +#include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/suspendibleThreadSet.hpp" #include "runtime/mutexLocker.hpp" @@ -100,22 +102,35 @@ void G1YoungRemSetSamplingThread::sample_young_list_rs_lengths() { G1CollectorPolicy* g1p = g1h->g1_policy(); if (g1p->adaptive_young_list_length()) { int regions_visited = 0; - g1h->young_list()->rs_length_sampling_init(); - while (g1h->young_list()->rs_length_sampling_more()) { - g1h->young_list()->rs_length_sampling_next(); + HeapRegion* hr = g1h->young_list()->first_region(); + size_t sampled_rs_lengths = 0; + + while (hr != NULL) { + size_t rs_length = hr->rem_set()->occupied(); + sampled_rs_lengths += rs_length; + + // The current region may not yet have been added to the + // incremental collection set (it gets added when it is + // retired as the current allocation region). + if (hr->in_collection_set()) { + // Update the collection set policy information for this region + g1p->update_incremental_cset_info(hr, rs_length); + } + ++regions_visited; // we try to yield every time we visit 10 regions if (regions_visited == 10) { if (sts.should_yield()) { sts.yield(); - // we just abandon the iteration - break; + // A gc may have occurred and our sampling data is stale and further + // traversal of the young list is unsafe + return; } regions_visited = 0; } + hr = hr->get_next_young_region(); } - - g1p->revise_young_list_target_length_if_necessary(); + g1p->revise_young_list_target_length_if_necessary(sampled_rs_lengths); } } diff --git a/hotspot/src/share/vm/gc/g1/youngList.cpp b/hotspot/src/share/vm/gc/g1/youngList.cpp index 3d95e8ff93a..25b9d21d4fa 100644 --- a/hotspot/src/share/vm/gc/g1/youngList.cpp +++ b/hotspot/src/share/vm/gc/g1/youngList.cpp @@ -33,9 +33,9 @@ #include "utilities/ostream.hpp" YoungList::YoungList(G1CollectedHeap* g1h) : - _g1h(g1h), _head(NULL), _length(0), _last_sampled_rs_lengths(0), + _g1h(g1h), _head(NULL), _length(0), _survivor_head(NULL), _survivor_tail(NULL), _survivor_length(0) { - guarantee(check_list_empty(false), "just making sure..."); + guarantee(check_list_empty(), "just making sure..."); } void YoungList::push_region(HeapRegion *hr) { @@ -86,9 +86,7 @@ void YoungList::empty_list() { _survivor_tail = NULL; _survivor_length = 0; - _last_sampled_rs_lengths = 0; - - assert(check_list_empty(false), "just making sure..."); + assert(check_list_empty(), "just making sure..."); } bool YoungList::check_list_well_formed() { @@ -119,17 +117,13 @@ bool YoungList::check_list_well_formed() { return ret; } -bool YoungList::check_list_empty(bool check_sample) { +bool YoungList::check_list_empty() { bool ret = true; if (_length != 0) { log_error(gc, verify)("### YOUNG LIST should have 0 length, not %u", _length); ret = false; } - if (check_sample && _last_sampled_rs_lengths != 0) { - log_error(gc, verify)("### YOUNG LIST has non-zero last sampled RS lengths"); - ret = false; - } if (_head != NULL) { log_error(gc, verify)("### YOUNG LIST does not have a NULL head"); ret = false; @@ -141,38 +135,6 @@ bool YoungList::check_list_empty(bool check_sample) { return ret; } -void -YoungList::rs_length_sampling_init() { - _sampled_rs_lengths = 0; - _curr = _head; -} - -bool -YoungList::rs_length_sampling_more() { - return _curr != NULL; -} - -void -YoungList::rs_length_sampling_next() { - assert( _curr != NULL, "invariant" ); - size_t rs_length = _curr->rem_set()->occupied(); - - _sampled_rs_lengths += rs_length; - - // The current region may not yet have been added to the - // incremental collection set (it gets added when it is - // retired as the current allocation region). - if (_curr->in_collection_set()) { - // Update the collection set policy information for this region - _g1h->g1_policy()->update_incremental_cset_info(_curr, rs_length); - } - - _curr = _curr->get_next_young_region(); - if (_curr == NULL) { - _last_sampled_rs_lengths = _sampled_rs_lengths; - } -} - void YoungList::reset_auxilary_lists() { guarantee( is_empty(), "young list should be empty" ); diff --git a/hotspot/src/share/vm/gc/g1/youngList.hpp b/hotspot/src/share/vm/gc/g1/youngList.hpp index 36108b807db..1030b3f9c1c 100644 --- a/hotspot/src/share/vm/gc/g1/youngList.hpp +++ b/hotspot/src/share/vm/gc/g1/youngList.hpp @@ -37,14 +37,9 @@ private: HeapRegion* _survivor_head; HeapRegion* _survivor_tail; - HeapRegion* _curr; - uint _length; uint _survivor_length; - size_t _last_sampled_rs_lengths; - size_t _sampled_rs_lengths; - void empty_list(HeapRegion* list); public: @@ -72,15 +67,6 @@ public: return (size_t) survivor_length() * HeapRegion::GrainBytes; } - void rs_length_sampling_init(); - bool rs_length_sampling_more(); - void rs_length_sampling_next(); - - void reset_sampled_info() { - _last_sampled_rs_lengths = 0; - } - size_t sampled_rs_lengths() { return _last_sampled_rs_lengths; } - // for development purposes void reset_auxilary_lists(); void clear() { _head = NULL; _length = 0; } @@ -97,7 +83,7 @@ public: // debugging bool check_list_well_formed(); - bool check_list_empty(bool check_sample = true); + bool check_list_empty(); void print(); }; From 4f6dba156809d016802eee6c3f128a173665a4b7 Mon Sep 17 00:00:00 2001 From: Max Ockner Date: Thu, 25 Feb 2016 13:09:17 -0500 Subject: [PATCH 075/183] 8150103: Convert TraceClassPaths to Unified Logging TraceClassPaths has been reimplemented with Unified Logging Reviewed-by: coleenp, dholmes, iklam --- .../src/share/vm/classfile/classLoader.cpp | 49 +++++++++---------- .../src/share/vm/classfile/classLoader.hpp | 4 +- .../vm/classfile/sharedPathsMiscInfo.cpp | 39 ++++++++++----- .../vm/classfile/sharedPathsMiscInfo.hpp | 19 +------ hotspot/src/share/vm/logging/logTag.hpp | 1 + hotspot/src/share/vm/memory/filemap.cpp | 20 +++----- hotspot/src/share/vm/runtime/arguments.cpp | 13 ++--- hotspot/src/share/vm/runtime/globals.hpp | 3 -- 8 files changed, 64 insertions(+), 84 deletions(-) diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index 14feb9876cf..0a1e20df3f0 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -37,6 +37,7 @@ #include "gc/shared/generation.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/oopMapCache.hpp" +#include "logging/logTag.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "memory/oopFactory.hpp" @@ -417,34 +418,30 @@ bool ClassPathImageEntry::is_jrt() { #if INCLUDE_CDS void ClassLoader::exit_with_path_failure(const char* error, const char* message) { assert(DumpSharedSpaces, "only called at dump time"); - tty->print_cr("Hint: enable -XX:+TraceClassPaths to diagnose the failure"); + tty->print_cr("Hint: enable -Xlog:classpath=info to diagnose the failure"); vm_exit_during_initialization(error, message); } #endif -void ClassLoader::trace_class_path(outputStream* out, const char* msg, const char* name) { - if (!TraceClassPaths) { - return; - } - - if (msg) { - out->print("%s", msg); - } - if (name) { - if (strlen(name) < 256) { - out->print("%s", name); - } else { - // For very long paths, we need to print each character separately, - // as print_cr() has a length limit - while (name[0] != '\0') { - out->print("%c", name[0]); - name++; +void ClassLoader::trace_class_path(const char* msg, const char* name) { + if (log_is_enabled(Info, classpath)) { + ResourceMark rm; + outputStream* out = LogHandle(classpath)::info_stream(); + if (msg) { + out->print("%s", msg); + } + if (name) { + if (strlen(name) < 256) { + out->print("%s", name); + } else { + // For very long paths, we need to print each character separately, + // as print_cr() has a length limit + while (name[0] != '\0') { + out->print("%c", name[0]); + name++; + } } } - } - if (msg && msg[0] == '[') { - out->print_cr("]"); - } else { out->cr(); } } @@ -470,11 +467,13 @@ void ClassLoader::check_shared_classpath(const char *path) { void ClassLoader::setup_bootstrap_search_path() { assert(_first_entry == NULL, "should not setup bootstrap class search path twice"); const char* sys_class_path = Arguments::get_sysclasspath(); + const char* java_class_path = Arguments::get_appclasspath(); if (PrintSharedArchiveAndExit) { // Don't print sys_class_path - this is the bootcp of this current VM process, not necessarily // the same as the bootcp of the shared archive. } else { - trace_class_path(tty, "[Bootstrap loader class path=", sys_class_path); + trace_class_path("bootstrap loader class path=", sys_class_path); + trace_class_path("classpath: ", java_class_path); } #if INCLUDE_CDS if (DumpSharedSpaces) { @@ -578,9 +577,7 @@ ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const str } } } - if (TraceClassPaths) { - tty->print_cr("[Opened %s]", path); - } + log_info(classpath)("opened: %s", path); log_info(classload)("opened: %s", path); } else { // Directory diff --git a/hotspot/src/share/vm/classfile/classLoader.hpp b/hotspot/src/share/vm/classfile/classLoader.hpp index 92ee90f2675..c2a68c04b09 100644 --- a/hotspot/src/share/vm/classfile/classLoader.hpp +++ b/hotspot/src/share/vm/classfile/classLoader.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -331,7 +331,7 @@ class ClassLoader: AllStatic { static void exit_with_path_failure(const char* error, const char* message); #endif - static void trace_class_path(outputStream* out, const char* msg, const char* name = NULL); + static void trace_class_path(const char* msg, const char* name = NULL); // VM monitoring and management support static jlong classloader_time_ms(); diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp index 9233e3243ad..40843700bd6 100644 --- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,15 +26,15 @@ #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/sharedPathsMiscInfo.hpp" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/metaspaceShared.hpp" #include "runtime/arguments.hpp" +#include "utilities/ostream.hpp" void SharedPathsMiscInfo::add_path(const char* path, int type) { - if (TraceClassPaths) { - tty->print("[type=%s] ", type_name(type)); - trace_class_path("[Add misc shared path ", path); - } + log_info(classpath)("type=%s ", type_name(type)); + ClassLoader::trace_class_path("add misc shared path ", path); write(path, strlen(path) + 1); write_jint(jint(type)); } @@ -67,11 +67,29 @@ bool SharedPathsMiscInfo::read(void* ptr, size_t size) { } bool SharedPathsMiscInfo::fail(const char* msg, const char* name) { - ClassLoader::trace_class_path(tty, msg, name); + ClassLoader::trace_class_path(msg, name); MetaspaceShared::set_archive_loading_failed(); return false; } +void SharedPathsMiscInfo::print_path(int type, const char* path) { + ResourceMark rm; + outputStream* out = LogHandle(classpath)::info_stream(); + switch (type) { + case BOOT: + out->print("Expecting -Dsun.boot.class.path=%s", path); + break; + case NON_EXIST: + out->print("Expecting that %s does not exist", path); + break; + case REQUIRED: + out->print("Expecting that file %s must exist and is not altered", path); + break; + default: + ShouldNotReachHere(); + } +} + bool SharedPathsMiscInfo::check() { // The whole buffer must be 0 terminated so that we can use strlen and strcmp // without fear. @@ -90,17 +108,14 @@ bool SharedPathsMiscInfo::check() { if (!read_jint(&type)) { return fail("Corrupted archive file header"); } - if (TraceClassPaths) { - tty->print("[type=%s ", type_name(type)); - print_path(tty, type, path); - tty->print_cr("]"); - } + log_info(classpath)("type=%s ", type_name(type)); + print_path(type, path); if (!check(type, path)) { if (!PrintSharedArchiveAndExit) { return false; } } else { - trace_class_path("[ok"); + ClassLoader::trace_class_path("ok"); } } diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp index 652d20c883a..435630febac 100644 --- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp @@ -64,9 +64,6 @@ protected: void write(const void* ptr, size_t size); bool read(void* ptr, size_t size); - static void trace_class_path(const char* msg, const char* name = NULL) { - ClassLoader::trace_class_path(tty, msg, name); - } protected: static bool fail(const char* msg, const char* name = NULL); virtual bool check(jint type, const char* path); @@ -144,21 +141,7 @@ public: } } - virtual void print_path(outputStream* out, int type, const char* path) { - switch (type) { - case BOOT: - out->print("Expecting -Dsun.boot.class.path=%s", path); - break; - case NON_EXIST: - out->print("Expecting that %s does not exist", path); - break; - case REQUIRED: - out->print("Expecting that file %s must exist and is not altered", path); - break; - default: - ShouldNotReachHere(); - } - } + virtual void print_path(int type, const char* path); bool check(); bool read_jint(jint *ptr) { diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp index 16a91cfbddf..08a78c6b2ba 100644 --- a/hotspot/src/share/vm/logging/logTag.hpp +++ b/hotspot/src/share/vm/logging/logTag.hpp @@ -43,6 +43,7 @@ LOG_TAG(classload) /* Trace all classes loaded */ \ LOG_TAG(classloaderdata) /* class loader loader_data lifetime */ \ LOG_TAG(classunload) /* Trace unloading of classes */ \ + LOG_TAG(classpath) \ LOG_TAG(compaction) \ LOG_TAG(cpu) \ LOG_TAG(cset) \ diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index 2a82e60c063..1b21736315c 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.cpp @@ -208,9 +208,7 @@ void FileMapInfo::allocate_classpath_entry_table() { count ++; bytes += (int)entry_size; bytes += name_bytes; - if (TraceClassPaths) { - tty->print_cr("[Add main shared path (%s) %s]", (cpe->is_jar_file() ? "jar" : "dir"), name); - } + log_info(classpath)("add main shared path (%s) %s", (cpe->is_jar_file() ? "jar" : "dir"), name); } else { SharedClassPathEntry* ent = shared_classpath(cur_entry); if (cpe->is_jar_file()) { @@ -275,9 +273,7 @@ bool FileMapInfo::validate_classpath_entry_table() { struct stat st; const char* name = ent->_name; bool ok = true; - if (TraceClassPaths) { - tty->print_cr("[Checking shared classpath entry: %s]", name); - } + log_info(classpath)("checking shared classpath entry: %s", name); if (os::stat(name, &st) != 0) { fail_continue("Required classpath entry does not exist: %s", name); ok = false; @@ -301,9 +297,7 @@ bool FileMapInfo::validate_classpath_entry_table() { } } if (ok) { - if (TraceClassPaths) { - tty->print_cr("[ok]"); - } + log_info(classpath)("ok"); } else if (!PrintSharedArchiveAndExit) { _validating_classpath_entry_table = false; return false; @@ -888,10 +882,8 @@ bool FileMapInfo::FileMapHeader::validate() { char header_version[JVM_IDENT_MAX]; get_header_version(header_version); if (strncmp(_jvm_ident, header_version, JVM_IDENT_MAX-1) != 0) { - if (TraceClassPaths) { - tty->print_cr("Expected: %s", header_version); - tty->print_cr("Actual: %s", _jvm_ident); - } + log_info(classpath)("expected: %s", header_version); + log_info(classpath)("actual: %s", _jvm_ident); FileMapInfo::fail_continue("The shared archive file was created by a different" " version or build of HotSpot"); return false; @@ -919,7 +911,7 @@ bool FileMapInfo::validate_header() { if (status) { if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size)) { if (!PrintSharedArchiveAndExit) { - fail_continue("shared class paths mismatch (hint: enable -XX:+TraceClassPaths to diagnose the failure)"); + fail_continue("shared class paths mismatch (hint: enable -Xlog:classpath=info to diagnose the failure)"); status = false; } } diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index f43a7a1372f..512c29fc94d 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -405,8 +405,9 @@ static AliasedFlag const aliased_jvm_flags[] = { static AliasedLoggingFlag const aliased_logging_flags[] = { { "TraceClassLoading", LogLevel::Info, true, LogTag::_classload }, - { "TraceClassUnloading", LogLevel::Info, true, LogTag::_classunload }, + { "TraceClassPaths", LogLevel::Info, true, LogTag::_classpath }, { "TraceClassResolution", LogLevel::Info, true, LogTag::_classresolve }, + { "TraceClassUnloading", LogLevel::Info, true, LogTag::_classunload }, { "TraceExceptions", LogLevel::Info, true, LogTag::_exceptions }, { "TraceMonitorInflation", LogLevel::Debug, true, LogTag::_monitorinflation }, { "TraceBiasedLocking", LogLevel::Info, true, LogTag::_biasedlocking }, @@ -3255,7 +3256,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, // PrintSharedArchiveAndExit will turn on // -Xshare:on - // -XX:+TraceClassPaths + // -Xlog:classpath=info if (PrintSharedArchiveAndExit) { if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) { return JNI_EINVAL; @@ -3263,9 +3264,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, TraceClassPaths, true) != Flag::SUCCESS) { - return JNI_EINVAL; - } + LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(classpath)); } // Change the default value for flags which have different default values @@ -3318,10 +3317,6 @@ void Arguments::fix_appclasspath() { _java_class_path->set_value(copy); FreeHeap(copy); // a copy was made by set_value, so don't need this anymore } - - if (!PrintSharedArchiveAndExit) { - ClassLoader::trace_class_path(tty, "[classpath: ", _java_class_path->value()); - } } static bool has_jar_files(const char* directory) { diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index ce36ff1db49..3c6219a4402 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -2403,9 +2403,6 @@ public: product(bool, IgnoreEmptyClassPaths, false, \ "Ignore empty path elements in -classpath") \ \ - product(bool, TraceClassPaths, false, \ - "Trace processing of class paths") \ - \ product(bool, TraceClassLoadingPreorder, false, \ "Trace all classes loaded in order referenced (not loaded)") \ \ From 917dc3b87c2d3fa0608727085a42189479a24c7e Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 26 Feb 2016 13:02:30 +0100 Subject: [PATCH 076/183] 8140777: Make Adaptive IHOP logging information the same as JFR logging Reviewed-by: tbenson, jmasa --- hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp index 0cf5dab9448..5759ed0c68f 100644 --- a/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp +++ b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -47,14 +47,16 @@ void G1IHOPControl::update_allocation_info(double allocation_time_s, size_t allo void G1IHOPControl::print() { size_t cur_conc_mark_start_threshold = get_conc_mark_start_threshold(); - log_debug(gc, ihop)("Basic information (value update), threshold: " SIZE_FORMAT "B (%1.2f), target occupancy: " SIZE_FORMAT "B, current occupancy: " SIZE_FORMAT "B," - " recent old gen allocation rate: %1.2f, recent marking phase length: %1.2f", + log_debug(gc, ihop)("Basic information (value update), threshold: " SIZE_FORMAT "B (%1.2f), target occupancy: " SIZE_FORMAT "B, current occupancy: " SIZE_FORMAT "B, " + "recent allocation size: " SIZE_FORMAT "B, recent allocation duration: %1.2fms, recent old gen allocation rate: %1.2fB/s, recent marking phase length: %1.2fms", cur_conc_mark_start_threshold, cur_conc_mark_start_threshold * 100.0 / _target_occupancy, _target_occupancy, G1CollectedHeap::heap()->used(), + _last_allocated_bytes, + _last_allocation_time_s * 1000.0, _last_allocation_time_s > 0.0 ? _last_allocated_bytes / _last_allocation_time_s : 0.0, - last_marking_length_s()); + last_marking_length_s() * 1000.0); } void G1IHOPControl::send_trace_event(G1NewTracer* tracer) { @@ -191,13 +193,16 @@ void G1AdaptiveIHOPControl::update_marking_length(double marking_length_s) { void G1AdaptiveIHOPControl::print() { G1IHOPControl::print(); size_t actual_target = actual_target_threshold(); - log_debug(gc, ihop)("Adaptive IHOP information (value update), threshold: " SIZE_FORMAT "B (%1.2f), internal target occupancy: " SIZE_FORMAT "B," - " predicted old gen allocation rate: %1.2f, predicted marking phase length: %1.2f, prediction active: %s", + log_debug(gc, ihop)("Adaptive IHOP information (value update), threshold: " SIZE_FORMAT "B (%1.2f), internal target occupancy: " SIZE_FORMAT "B, " + "occupancy: " SIZE_FORMAT "B, additional buffer size: " SIZE_FORMAT "B, predicted old gen allocation rate: %1.2fB/s, " + "predicted marking phase length: %1.2fms, prediction active: %s", get_conc_mark_start_threshold(), percent_of(get_conc_mark_start_threshold(), actual_target), actual_target, + G1CollectedHeap::heap()->used(), + _last_unrestrained_young_size, _predictor->get_new_prediction(&_allocation_rate_s), - _predictor->get_new_prediction(&_marking_times_s), + _predictor->get_new_prediction(&_marking_times_s) * 1000.0, have_enough_data_for_prediction() ? "true" : "false"); } From d00c7378d6fd9b41ae66fece438c1975bf1d835b Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 26 Feb 2016 13:02:30 +0100 Subject: [PATCH 077/183] 8076463: Add logging for the preserve CM referents task Add logging and do minor refactoring to CM referents handling task. Reviewed-by: jmasa --- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 25 +++++++++++++------ .../src/share/vm/gc/g1/g1CollectedHeap.hpp | 3 +++ hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp | 6 ++++- hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp | 9 ++++++- hotspot/test/gc/g1/TestGCLogMessages.java | 6 +++-- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index f241d749045..860df5306a5 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -4398,6 +4398,8 @@ public: { } void work(uint worker_id) { + G1GCParPhaseTimesTracker x(_g1h->g1_policy()->phase_times(), G1GCPhaseTimes::PreserveCMReferents, worker_id); + ResourceMark rm; HandleMark hm; @@ -4461,13 +4463,8 @@ void G1CollectedHeap::process_weak_jni_handles() { g1_policy()->phase_times()->record_ref_proc_time(ref_proc_time * 1000.0); } -// Weak Reference processing during an evacuation pause (part 1). -void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per_thread_states) { - double ref_proc_start = os::elapsedTime(); - - ReferenceProcessor* rp = _ref_processor_stw; - assert(rp->discovery_enabled(), "should have been enabled"); - +void G1CollectedHeap::preserve_cm_referents(G1ParScanThreadStateSet* per_thread_states) { + double preserve_cm_referents_start = os::elapsedTime(); // Any reference objects, in the collection set, that were 'discovered' // by the CM ref processor should have already been copied (either by // applying the external root copy closure to the discovered lists, or @@ -4495,9 +4492,18 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per per_thread_states, no_of_gc_workers, _task_queues); - workers()->run_task(&keep_cm_referents); + g1_policy()->phase_times()->record_preserve_cm_referents_time_ms((os::elapsedTime() - preserve_cm_referents_start) * 1000.0); +} + +// Weak Reference processing during an evacuation pause (part 1). +void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per_thread_states) { + double ref_proc_start = os::elapsedTime(); + + ReferenceProcessor* rp = _ref_processor_stw; + assert(rp->discovery_enabled(), "should have been enabled"); + // Closure to test whether a referent is alive. G1STWIsAliveClosure is_alive(this); @@ -4529,6 +4535,8 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per NULL, _gc_timer_stw); } else { + uint no_of_gc_workers = workers()->active_workers(); + // Parallel reference processing assert(rp->num_q() == no_of_gc_workers, "sanity"); assert(no_of_gc_workers <= rp->max_num_q(), "sanity"); @@ -4644,6 +4652,7 @@ void G1CollectedHeap::post_evacuate_collection_set(EvacuationInfo& evacuation_in // objects (and their reachable sub-graphs) that were // not copied during the pause. if (g1_policy()->should_process_references()) { + preserve_cm_referents(per_thread_states); process_discovered_references(per_thread_states); } else { ref_processor_stw()->verify_no_references_recorded(); diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index 3d8badc27bb..f381ee5b7db 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -511,6 +511,9 @@ protected: // allocated block, or else "NULL". HeapWord* expand_and_allocate(size_t word_size, AllocationContext_t context); + // Preserve any referents discovered by concurrent marking that have not yet been + // copied by the STW pause. + void preserve_cm_referents(G1ParScanThreadStateSet* per_thread_states); // Process any reference objects discovered during // an incremental evacuation pause. void process_discovered_references(G1ParScanThreadStateSet* per_thread_states); diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp index 706495fdbc7..8fefab03f65 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, 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 @@ -129,6 +129,8 @@ G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : _gc_par_phases[RedirtyCards] = new WorkerDataArray(max_gc_threads, "Parallel Redirty:", true, 3); _redirtied_cards = new WorkerDataArray(max_gc_threads, "Redirtied Cards:", true, 3); _gc_par_phases[RedirtyCards]->link_thread_work_items(_redirtied_cards); + + _gc_par_phases[PreserveCMReferents] = new WorkerDataArray(max_gc_threads, "Parallel Preserve CM Refs:", true, 3); } void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) { @@ -392,10 +394,12 @@ void G1GCPhaseTimes::print() { print_stats(Indents[2], "Choose CSet", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms)); + print_stats(Indents[2], "Preserve CM Refs", _recorded_preserve_cm_referents_time_ms); print_stats(Indents[2], "Ref Proc", _cur_ref_proc_time_ms); print_stats(Indents[2], "Ref Enq", _cur_ref_enq_time_ms); print_stats(Indents[2], "Redirty Cards", _recorded_redirty_logged_cards_time_ms); par_phase_printer.print(RedirtyCards); + par_phase_printer.print(PreserveCMReferents); if (G1EagerReclaimHumongousObjects) { print_stats(Indents[2], "Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp index 5607c3f4ea0..a4e6ff1dec5 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, 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 @@ -69,6 +69,7 @@ class G1GCPhaseTimes : public CHeapObj { StringDedupQueueFixup, StringDedupTableFixup, RedirtyCards, + PreserveCMReferents, GCParPhasesSentinel }; @@ -108,6 +109,8 @@ class G1GCPhaseTimes : public CHeapObj { double _recorded_redirty_logged_cards_time_ms; + double _recorded_preserve_cm_referents_time_ms; + double _recorded_young_free_cset_time_ms; double _recorded_non_young_free_cset_time_ms; @@ -234,6 +237,10 @@ class G1GCPhaseTimes : public CHeapObj { _recorded_redirty_logged_cards_time_ms = time_ms; } + void record_preserve_cm_referents_time_ms(double time_ms) { + _recorded_preserve_cm_referents_time_ms = time_ms; + } + void record_cur_collection_start_sec(double time_ms) { _cur_collection_start_sec = time_ms; } diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index 8ab921b0186..c0f83fc1fe0 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test TestGCLogMessages - * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 8069330 + * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 8069330 8076463 * @summary Ensure the output for a minor GC with G1 * includes the expected necessary messages. * @key gc @@ -86,6 +86,8 @@ public class TestGCLogMessages { // Humongous Eager Reclaim new LogMessageWithLevel("Humongous Reclaim", Level.DEBUG), new LogMessageWithLevel("Humongous Register", Level.DEBUG), + // Preserve CM Referents + new LogMessageWithLevel("Preserve CM Refs", Level.DEBUG), }; void checkMessagesAtLevel(OutputAnalyzer output, LogMessageWithLevel messages[], Level level) throws Exception { From 6fe8d6e7de9f68558d8350c12935eb28095bbec9 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 26 Feb 2016 13:02:30 +0100 Subject: [PATCH 078/183] 8150630: Add logging for ParScanThreadState merge phase Improve visibility of the per-thread scan state merge phase by adding appropriate logging. Reviewed-by: jmasa, tbenson --- hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp | 8 +++++++- hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp | 3 +++ hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp | 1 + hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp | 6 ++++++ hotspot/test/gc/g1/TestGCLogMessages.java | 4 +++- 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index 860df5306a5..6b1f7f0d389 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -4594,6 +4594,12 @@ void G1CollectedHeap::enqueue_discovered_references(G1ParScanThreadStateSet* per g1_policy()->phase_times()->record_ref_enq_time(ref_enq_time * 1000.0); } +void G1CollectedHeap::merge_per_thread_state_info(G1ParScanThreadStateSet* per_thread_states) { + double merge_pss_time_start = os::elapsedTime(); + per_thread_states->flush(); + g1_policy()->phase_times()->record_merge_pss_time_ms((os::elapsedTime() - merge_pss_time_start) * 1000.0); +} + void G1CollectedHeap::pre_evacuate_collection_set() { _expand_heap_after_alloc_failure = true; _evacuation_failed = false; @@ -4696,7 +4702,7 @@ void G1CollectedHeap::post_evacuate_collection_set(EvacuationInfo& evacuation_in _allocator->release_gc_alloc_regions(evacuation_info); - per_thread_states->flush(); + merge_per_thread_state_info(per_thread_states); record_obj_copy_mem_stats(); diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index f381ee5b7db..bce50eb7a5b 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -522,6 +522,9 @@ protected: // after processing. void enqueue_discovered_references(G1ParScanThreadStateSet* per_thread_states); + // Merges the information gathered on a per-thread basis for all worker threads + // during GC into global variables. + void merge_per_thread_state_info(G1ParScanThreadStateSet* per_thread_states); public: WorkGang* workers() const { return _workers; } diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp index 8fefab03f65..e8c852b051f 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp @@ -413,6 +413,7 @@ void G1GCPhaseTimes::print() { _recorded_non_young_free_cset_time_ms)); log_trace(gc, phases)("%sYoung Free CSet: %.1lf ms", Indents[3], _recorded_young_free_cset_time_ms); log_trace(gc, phases)("%sNon-Young Free CSet: %.1lf ms", Indents[3], _recorded_non_young_free_cset_time_ms); + print_stats(Indents[2], "Merge Per-Thread State", _recorded_merge_pss_time_ms); if (_cur_verify_after_time_ms > 0.0) { print_stats(Indents[2], "Verify After", _cur_verify_after_time_ms); } diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp index a4e6ff1dec5..c474659a849 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp @@ -111,6 +111,8 @@ class G1GCPhaseTimes : public CHeapObj { double _recorded_preserve_cm_referents_time_ms; + double _recorded_merge_pss_time_ms; + double _recorded_young_free_cset_time_ms; double _recorded_non_young_free_cset_time_ms; @@ -241,6 +243,10 @@ class G1GCPhaseTimes : public CHeapObj { _recorded_preserve_cm_referents_time_ms = time_ms; } + void record_merge_pss_time_ms(double time_ms) { + _recorded_merge_pss_time_ms = time_ms; + } + void record_cur_collection_start_sec(double time_ms) { _cur_collection_start_sec = time_ms; } diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index c0f83fc1fe0..0659c98f1c9 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -23,7 +23,7 @@ /* * @test TestGCLogMessages - * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 8069330 8076463 + * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 8069330 8076463 8150630 * @summary Ensure the output for a minor GC with G1 * includes the expected necessary messages. * @key gc @@ -88,6 +88,8 @@ public class TestGCLogMessages { new LogMessageWithLevel("Humongous Register", Level.DEBUG), // Preserve CM Referents new LogMessageWithLevel("Preserve CM Refs", Level.DEBUG), + // Merge PSS + new LogMessageWithLevel("Merge Per-Thread State", Level.DEBUG), }; void checkMessagesAtLevel(OutputAnalyzer output, LogMessageWithLevel messages[], Level level) throws Exception { From d090b747441eaec656cc785e165e61bda27bf037 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 26 Feb 2016 13:02:30 +0100 Subject: [PATCH 079/183] 8150629: Initializing all ParScanThreadStates causes significant unaccounted "Other" times Lazily allocate ParScanThreadStates within the worker threads instead of doing this work upfront serially. Reviewed-by: mgerdin, jmasa --- hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp | 9 ++++++++- hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp | 6 ++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp index f22c6e2195c..b59fc203c6c 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, 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 @@ -327,6 +327,9 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state, G1ParScanThreadState* G1ParScanThreadStateSet::state_for_worker(uint worker_id) { assert(worker_id < _n_workers, "out of bounds access"); + if (_states[worker_id] == NULL) { + _states[worker_id] = new_par_scan_state(worker_id, _young_cset_length); + } return _states[worker_id]; } @@ -352,6 +355,10 @@ void G1ParScanThreadStateSet::flush() { for (uint worker_index = 0; worker_index < _n_workers; ++worker_index) { G1ParScanThreadState* pss = _states[worker_index]; + if (pss == NULL) { + continue; + } + _total_cards_scanned += _cards_scanned[worker_index]; pss->flush(_surviving_young_words_total); diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp index 47c5328d2b9..6accb48c1de 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, 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 @@ -200,6 +200,7 @@ class G1ParScanThreadStateSet : public StackObj { size_t* _surviving_young_words_total; size_t* _cards_scanned; size_t _total_cards_scanned; + size_t _young_cset_length; uint _n_workers; bool _flushed; @@ -210,10 +211,11 @@ class G1ParScanThreadStateSet : public StackObj { _surviving_young_words_total(NEW_C_HEAP_ARRAY(size_t, young_cset_length, mtGC)), _cards_scanned(NEW_C_HEAP_ARRAY(size_t, n_workers, mtGC)), _total_cards_scanned(0), + _young_cset_length(young_cset_length), _n_workers(n_workers), _flushed(false) { for (uint i = 0; i < n_workers; ++i) { - _states[i] = new_par_scan_state(i, young_cset_length); + _states[i] = NULL; } memset(_surviving_young_words_total, 0, young_cset_length * sizeof(size_t)); memset(_cards_scanned, 0, n_workers * sizeof(size_t)); From 8cc9a5146bd92919ef836da698a5c75aa0c99efe Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Fri, 26 Feb 2016 13:21:28 +0100 Subject: [PATCH 080/183] 8150727: [JVMCI] add LoadLoad to the implicit memory barriers on AMD64 Reviewed-by: rschatz, twisti --- .../classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java index 37393ff08bc..972aea94231 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java @@ -22,6 +22,7 @@ */ package jdk.vm.ci.amd64; +import static jdk.vm.ci.code.MemoryBarriers.LOAD_LOAD; import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE; import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE; import static jdk.vm.ci.code.Register.SPECIAL; @@ -220,7 +221,7 @@ public class AMD64 extends Architecture { private final AMD64Kind largestKind; public AMD64(EnumSet features, EnumSet flags) { - super("AMD64", AMD64Kind.QWORD, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_STORE | STORE_STORE, 1, 8); + super("AMD64", AMD64Kind.QWORD, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_LOAD | LOAD_STORE | STORE_STORE, 1, 8); this.features = features; this.flags = flags; assert features.contains(CPUFeature.SSE2) : "minimum config for x64"; From 62c5bdbe9de1c89cc28184badcc50cfe888c1185 Mon Sep 17 00:00:00 2001 From: Andreas Eriksson Date: Fri, 26 Feb 2016 16:28:42 +0100 Subject: [PATCH 081/183] 8144732: VM_HeapDumper hits assert with bad dump_len Reviewed-by: dsamersoff --- hotspot/src/share/vm/runtime/arguments.cpp | 1 + hotspot/src/share/vm/runtime/globals.hpp | 4 - hotspot/src/share/vm/services/heapDumper.cpp | 256 +++++++++++-------- 3 files changed, 149 insertions(+), 112 deletions(-) diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 512c29fc94d..322516b9ef4 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -372,6 +372,7 @@ static SpecialFlag const special_jvm_flags[] = { { "PreInflateSpin", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "JNIDetachReleasesMonitors", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "UseAltSigs", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, + { "SegmentedHeapDumpThreshold", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, #ifdef TEST_VERIFY_SPECIAL_JVM_FLAGS { "dep > obs", JDK_Version::jdk(9), JDK_Version::jdk(8), JDK_Version::undefined() }, diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 3c6219a4402..848bb5d2607 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1055,10 +1055,6 @@ public: "directory) of the dump file (defaults to java_pid.hprof " \ "in the working directory)") \ \ - develop(size_t, SegmentedHeapDumpThreshold, 2*G, \ - "Generate a segmented heap dump (JAVA PROFILE 1.0.2 format) " \ - "when the heap usage is larger than this") \ - \ develop(size_t, HeapDumpSegmentSize, 1*G, \ "Approximate segment size when generating a segmented heap dump") \ \ diff --git a/hotspot/src/share/vm/services/heapDumper.cpp b/hotspot/src/share/vm/services/heapDumper.cpp index 2f01fab4cc9..986855894d2 100644 --- a/hotspot/src/share/vm/services/heapDumper.cpp +++ b/hotspot/src/share/vm/services/heapDumper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, 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 @@ -53,8 +53,7 @@ * src/share/demo/jvmti/hprof/hprof_io.c * * - * header "JAVA PROFILE 1.0.1" or "JAVA PROFILE 1.0.2" - * (0-terminated) + * header "JAVA PROFILE 1.0.2" (0-terminated) * * u4 size of identifiers. Identifiers are used to represent * UTF8 strings, objects, stack traces, etc. They usually @@ -385,6 +384,8 @@ class DumpWriter : public StackObj { size_t _size; size_t _pos; + jlong _dump_start; + char* _error; // error message when I/O fails void set_file_descriptor(int fd) { _fd = fd; } @@ -408,6 +409,10 @@ class DumpWriter : public StackObj { bool is_open() const { return file_descriptor() >= 0; } void flush(); + jlong dump_start() const { return _dump_start; } + void set_dump_start(jlong pos); + julong current_record_length(); + // total number of bytes written to the disk julong bytes_written() const { return _bytes_written; } @@ -449,6 +454,7 @@ DumpWriter::DumpWriter(const char* path) { _pos = 0; _error = NULL; _bytes_written = 0L; + _dump_start = (jlong)-1; _fd = os::create_binary_file(path, false); // don't replace existing file // if the open failed we record the error @@ -476,6 +482,22 @@ void DumpWriter::close() { } } +// sets the dump starting position +void DumpWriter::set_dump_start(jlong pos) { + _dump_start = pos; +} + +julong DumpWriter::current_record_length() { + if (is_open()) { + // calculate the size of the dump record + julong dump_end = bytes_written() + bytes_unwritten(); + assert(dump_end == (size_t)current_offset(), "checking"); + julong dump_len = dump_end - dump_start() - 4; + return dump_len; + } + return 0; +} + // write directly to the file void DumpWriter::write_internal(void* s, size_t len) { if (is_open()) { @@ -645,6 +667,18 @@ class DumperSupport : AllStatic { static void dump_prim_array(DumpWriter* writer, typeArrayOop array); // create HPROF_FRAME record for the given method and bci static void dump_stack_frame(DumpWriter* writer, int frame_serial_num, int class_serial_num, Method* m, int bci); + + // check if we need to truncate an array + static int calculate_array_max_length(DumpWriter* writer, arrayOop array, short header_size); + + // writes a HPROF_HEAP_DUMP_SEGMENT record + static void write_dump_header(DumpWriter* writer); + + // fixes up the length of the current dump record + static void write_current_dump_record_length(DumpWriter* writer); + + // fixes up the current dump record and writes HPROF_HEAP_DUMP_END record + static void end_of_dump(DumpWriter* writer); }; // write a header of the given type @@ -1005,50 +1039,102 @@ void DumperSupport::dump_basic_type_array_class(DumpWriter* writer, Klass* k) { } } +// Hprof uses an u4 as record length field, +// which means we need to truncate arrays that are too long. +int DumperSupport::calculate_array_max_length(DumpWriter* writer, arrayOop array, short header_size) { + BasicType type = ArrayKlass::cast(array->klass())->element_type(); + assert(type >= T_BOOLEAN && type <= T_OBJECT, "invalid array element type"); + + int length = array->length(); + + int type_size; + if (type == T_OBJECT) { + type_size = sizeof(address); + } else { + type_size = type2aelembytes(type); + } + + size_t length_in_bytes = (size_t)length * type_size; + + // Create a new record if the current record is non-empty and the array can't fit. + julong current_record_length = writer->current_record_length(); + if (current_record_length > 0 && + (current_record_length + header_size + length_in_bytes) > max_juint) { + write_current_dump_record_length(writer); + write_dump_header(writer); + + // We now have an empty record. + current_record_length = 0; + } + + // Calculate max bytes we can use. + uint max_bytes = max_juint - (header_size + current_record_length); + + // Array too long for the record? + // Calculate max length and return it. + if (length_in_bytes > max_bytes) { + length = max_bytes / type_size; + length_in_bytes = (size_t)length * type_size; + + warning("cannot dump array of type %s[] with length %d; truncating to length %d", + type2name_tab[type], array->length(), length); + } + return length; +} + // creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array void DumperSupport::dump_object_array(DumpWriter* writer, objArrayOop array) { + // sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID) + sizeof(classID) + short header_size = 1 + 2 * 4 + 2 * sizeof(address); + + int length = calculate_array_max_length(writer, array, header_size); writer->write_u1(HPROF_GC_OBJ_ARRAY_DUMP); writer->write_objectID(array); writer->write_u4(STACK_TRACE_ID); - writer->write_u4((u4)array->length()); + writer->write_u4(length); // array class ID writer->write_classID(array->klass()); // [id]* elements - for (int index=0; indexlength(); index++) { + for (int index = 0; index < length; index++) { oop o = array->obj_at(index); writer->write_objectID(o); } } -#define WRITE_ARRAY(Array, Type, Size) \ - for (int i=0; ilength(); i++) { writer->write_##Size((Size)array->Type##_at(i)); } - +#define WRITE_ARRAY(Array, Type, Size, Length) \ + for (int i = 0; i < Length; i++) { writer->write_##Size((Size)Array->Type##_at(i)); } // creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { BasicType type = TypeArrayKlass::cast(array->klass())->element_type(); + // 2 * sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID) + short header_size = 2 * 1 + 2 * 4 + sizeof(address); + + int length = calculate_array_max_length(writer, array, header_size); + int type_size = type2aelembytes(type); + u4 length_in_bytes = (u4)length * type_size; + writer->write_u1(HPROF_GC_PRIM_ARRAY_DUMP); writer->write_objectID(array); writer->write_u4(STACK_TRACE_ID); - writer->write_u4((u4)array->length()); + writer->write_u4(length); writer->write_u1(type2tag(type)); // nothing to copy - if (array->length() == 0) { + if (length == 0) { return; } // If the byte ordering is big endian then we can copy most types directly - u4 length_in_bytes = (u4)array->length() * type2aelembytes(type); switch (type) { case T_INT : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, int, u4); + WRITE_ARRAY(array, int, u4, length); } else { writer->write_raw((void*)(array->int_at_addr(0)), length_in_bytes); } @@ -1060,7 +1146,7 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { } case T_CHAR : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, char, u2); + WRITE_ARRAY(array, char, u2, length); } else { writer->write_raw((void*)(array->char_at_addr(0)), length_in_bytes); } @@ -1068,7 +1154,7 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { } case T_SHORT : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, short, u2); + WRITE_ARRAY(array, short, u2, length); } else { writer->write_raw((void*)(array->short_at_addr(0)), length_in_bytes); } @@ -1076,7 +1162,7 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { } case T_BOOLEAN : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, bool, u1); + WRITE_ARRAY(array, bool, u1, length); } else { writer->write_raw((void*)(array->bool_at_addr(0)), length_in_bytes); } @@ -1084,7 +1170,7 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { } case T_LONG : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, long, u8); + WRITE_ARRAY(array, long, u8, length); } else { writer->write_raw((void*)(array->long_at_addr(0)), length_in_bytes); } @@ -1096,14 +1182,14 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { // use IEEE 754. case T_FLOAT : { - for (int i=0; ilength(); i++) { - dump_float( writer, array->float_at(i) ); + for (int i = 0; i < length; i++) { + dump_float(writer, array->float_at(i)); } break; } case T_DOUBLE : { - for (int i=0; ilength(); i++) { - dump_double( writer, array->double_at(i) ); + for (int i = 0; i < length; i++) { + dump_double(writer, array->double_at(i)); } break; } @@ -1320,8 +1406,6 @@ class VM_HeapDumper : public VM_GC_Operation { JavaThread* _oome_thread; Method* _oome_constructor; bool _gc_before_heap_dump; - bool _is_segmented_dump; - jlong _dump_start; GrowableArray* _klass_map; ThreadStackTrace** _stack_traces; int _num_threads; @@ -1340,11 +1424,6 @@ class VM_HeapDumper : public VM_GC_Operation { void clear_global_dumper() { _global_dumper = NULL; } void clear_global_writer() { _global_writer = NULL; } - bool is_segmented_dump() const { return _is_segmented_dump; } - void set_segmented_dump() { _is_segmented_dump = true; } - jlong dump_start() const { return _dump_start; } - void set_dump_start(jlong pos); - bool skip_operation() const; // writes a HPROF_LOAD_CLASS record @@ -1369,16 +1448,6 @@ class VM_HeapDumper : public VM_GC_Operation { // HPROF_TRACE and HPROF_FRAME records void dump_stack_traces(); - // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record - void write_dump_header(); - - // fixes up the length of the current dump record - void write_current_dump_record_length(); - - // fixes up the current dump record )and writes HPROF_HEAP_DUMP_END - // record in the case of a segmented heap dump) - void end_of_dump(); - public: VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump, bool oome) : VM_GC_Operation(0 /* total collections, dummy, ignored */, @@ -1387,8 +1456,6 @@ class VM_HeapDumper : public VM_GC_Operation { gc_before_heap_dump) { _local_writer = writer; _gc_before_heap_dump = gc_before_heap_dump; - _is_segmented_dump = false; - _dump_start = (jlong)-1; _klass_map = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(INITIAL_CLASS_COUNT, true); _stack_traces = NULL; _num_threads = 0; @@ -1428,35 +1495,23 @@ bool VM_HeapDumper::skip_operation() const { return false; } -// sets the dump starting position -void VM_HeapDumper::set_dump_start(jlong pos) { - _dump_start = pos; -} - - // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record -void VM_HeapDumper::write_dump_header() { - if (writer()->is_open()) { - if (is_segmented_dump()) { - writer()->write_u1(HPROF_HEAP_DUMP_SEGMENT); - } else { - writer()->write_u1(HPROF_HEAP_DUMP); - } - writer()->write_u4(0); // current ticks + // writes a HPROF_HEAP_DUMP_SEGMENT record +void DumperSupport::write_dump_header(DumpWriter* writer) { + if (writer->is_open()) { + writer->write_u1(HPROF_HEAP_DUMP_SEGMENT); + writer->write_u4(0); // current ticks // record the starting position for the dump (its length will be fixed up later) - set_dump_start(writer()->current_offset()); - writer()->write_u4(0); + writer->set_dump_start(writer->current_offset()); + writer->write_u4(0); } } // fixes up the length of the current dump record -void VM_HeapDumper::write_current_dump_record_length() { - if (writer()->is_open()) { - assert(dump_start() >= 0, "no dump start recorded"); - - // calculate the size of the dump record - julong dump_end = writer()->current_offset(); - julong dump_len = (dump_end - dump_start() - 4); +void DumperSupport::write_current_dump_record_length(DumpWriter* writer) { + if (writer->is_open()) { + julong dump_end = writer->bytes_written() + writer->bytes_unwritten(); + julong dump_len = writer->current_record_length(); // record length must fit in a u4 if (dump_len > max_juint) { @@ -1464,17 +1519,18 @@ void VM_HeapDumper::write_current_dump_record_length() { } // seek to the dump start and fix-up the length - writer()->seek_to_offset(dump_start()); - writer()->write_u4((u4)dump_len); + assert(writer->dump_start() >= 0, "no dump start recorded"); + writer->seek_to_offset(writer->dump_start()); + writer->write_u4((u4)dump_len); // adjust the total size written to keep the bytes written correct. - writer()->adjust_bytes_written(-((jlong) sizeof(u4))); + writer->adjust_bytes_written(-((jlong) sizeof(u4))); // seek to dump end so we can continue - writer()->seek_to_offset(dump_end); + writer->seek_to_offset(dump_end); // no current dump record - set_dump_start((jlong)-1); + writer->set_dump_start((jlong)-1); } } @@ -1482,33 +1538,23 @@ void VM_HeapDumper::write_current_dump_record_length() { // new segment. void VM_HeapDumper::check_segment_length() { if (writer()->is_open()) { - if (is_segmented_dump()) { - // don't use current_offset that would be too expensive on a per record basis - julong dump_end = writer()->bytes_written() + writer()->bytes_unwritten(); - assert(dump_end == (julong)writer()->current_offset(), "checking"); - julong dump_len = (dump_end - dump_start() - 4); - assert(dump_len <= max_juint, "bad dump length"); + julong dump_len = writer()->current_record_length(); - if (dump_len > HeapDumpSegmentSize) { - write_current_dump_record_length(); - write_dump_header(); - } + if (dump_len > 2UL*G) { + DumperSupport::write_current_dump_record_length(writer()); + DumperSupport::write_dump_header(writer()); } } } -// fixes up the current dump record )and writes HPROF_HEAP_DUMP_END -// record in the case of a segmented heap dump) -void VM_HeapDumper::end_of_dump() { - if (writer()->is_open()) { - write_current_dump_record_length(); +// fixes up the current dump record and writes HPROF_HEAP_DUMP_END record +void DumperSupport::end_of_dump(DumpWriter* writer) { + if (writer->is_open()) { + write_current_dump_record_length(writer); - // for segmented dump we write the end record - if (is_segmented_dump()) { - writer()->write_u1(HPROF_HEAP_DUMP_END); - writer()->write_u4(0); - writer()->write_u4(0); - } + writer->write_u1(HPROF_HEAP_DUMP_END); + writer->write_u4(0); + writer->write_u4(0); } } @@ -1686,16 +1732,17 @@ void VM_HeapDumper::do_threads() { // [HPROF_LOAD_CLASS]* // [[HPROF_FRAME]*|HPROF_TRACE]* // [HPROF_GC_CLASS_DUMP]* -// HPROF_HEAP_DUMP +// [HPROF_HEAP_DUMP_SEGMENT]* +// HPROF_HEAP_DUMP_END // // The HPROF_TRACE records represent the stack traces where the heap dump // is generated and a "dummy trace" record which does not include // any frames. The dummy trace record is used to be referenced as the // unknown object alloc site. // -// The HPROF_HEAP_DUMP record has a length following by sub-records. To allow -// the heap dump be generated in a single pass we remember the position of -// the dump length and fix it up after all sub-records have been written. +// Each HPROF_HEAP_DUMP_SEGMENT record has a length followed by sub-records. +// To allow the heap dump be generated in a single pass we remember the position +// of the dump length and fix it up after all sub-records have been written. // To generate the sub-records we iterate over the heap, writing // HPROF_GC_INSTANCE_DUMP, HPROF_GC_OBJ_ARRAY_DUMP, and HPROF_GC_PRIM_ARRAY_DUMP // records as we go. Once that is done we write records for some of the GC @@ -1722,15 +1769,9 @@ void VM_HeapDumper::doit() { set_global_dumper(); set_global_writer(); - // Write the file header - use 1.0.2 for large heaps, otherwise 1.0.1 + // Write the file header - we always use 1.0.2 size_t used = ch->used(); - const char* header; - if (used > SegmentedHeapDumpThreshold) { - set_segmented_dump(); - header = "JAVA PROFILE 1.0.2"; - } else { - header = "JAVA PROFILE 1.0.1"; - } + const char* header = "JAVA PROFILE 1.0.2"; // header is few bytes long - no chance to overflow int writer()->write_raw((void*)header, (int)strlen(header)); @@ -1750,8 +1791,8 @@ void VM_HeapDumper::doit() { // this must be called after _klass_map is built when iterating the classes above. dump_stack_traces(); - // write HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT - write_dump_header(); + // write HPROF_HEAP_DUMP_SEGMENT + DumperSupport::write_dump_header(writer()); // Writes HPROF_GC_CLASS_DUMP records ClassLoaderDataGraph::classes_do(&do_class_dump); @@ -1759,9 +1800,9 @@ void VM_HeapDumper::doit() { check_segment_length(); // writes HPROF_GC_INSTANCE_DUMP records. - // After each sub-record is written check_segment_length will be invoked. When - // generated a segmented heap dump this allows us to check if the current - // segment exceeds a threshold and if so, then a new segment is started. + // After each sub-record is written check_segment_length will be invoked + // to check if the current segment exceeds a threshold. If so, a new + // segment is started. // The HPROF_GC_CLASS_DUMP and HPROF_GC_INSTANCE_DUMP are the vast bulk // of the heap dump. HeapObjectDumper obj_dumper(this, writer()); @@ -1785,9 +1826,8 @@ void VM_HeapDumper::doit() { StickyClassDumper class_dumper(writer()); SystemDictionary::always_strong_classes_do(&class_dumper); - // fixes up the length of the dump record. In the case of a segmented - // heap then the HPROF_HEAP_DUMP_END record is also written. - end_of_dump(); + // fixes up the length of the dump record and writes the HPROF_HEAP_DUMP_END record. + DumperSupport::end_of_dump(writer()); // Now we clear the global variables, so that a future dumper might run. clear_global_dumper(); From 5d211651719ad5edc31b1231d03064885c03f629 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 26 Feb 2016 18:51:44 +0300 Subject: [PATCH 082/183] 8141553: [macosx] JDK fails to build with Xcode 7 on 10.11 Reviewed-by: aniyogi, ddehaven, cbensen --- .../macosx/native/libawt_lwawt/awt/AWTView.m | 7 +++--- .../native/libawt_lwawt/awt/LWCToolkit.m | 7 +++--- .../macosx/native/libosx/CFileManager.m | 22 +++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m index 805596cc118..8070995baa6 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, 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 @@ -624,7 +624,8 @@ AWT_ASSERT_APPKIT_THREAD; { NSString *selectedText = [self accessibleSelectedText]; NSAttributedString *styledText = [[NSAttributedString alloc] initWithString:selectedText]; - NSData *rtfdData = [styledText RTFDFromRange:NSMakeRange(0, [styledText length]) documentAttributes:nil]; + NSData *rtfdData = [styledText RTFDFromRange:NSMakeRange(0, [styledText length]) + documentAttributes:@{NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType}]; [styledText release]; return rtfdData; } @@ -681,7 +682,7 @@ AWT_ASSERT_APPKIT_THREAD; if ([[pboard types] containsObject:NSRTFDPboardType]) { NSData *rtfdData = [pboard dataForType:NSRTFDPboardType]; - NSAttributedString *styledText = [[NSAttributedString alloc] initWithRTFD:rtfdData documentAttributes:nil]; + NSAttributedString *styledText = [[NSAttributedString alloc] initWithRTFD:rtfdData documentAttributes:NULL]; NSString *text = [styledText string]; [styledText release]; diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m index 8f1e269de8f..9d8326ade6d 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, 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 @@ -743,9 +743,10 @@ Java_sun_lwawt_macosx_LWCToolkit_initAppkit JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *vm, void *reserved) { OSXAPP_SetJavaVM(vm); - // We need to let Foundation know that this is a multithreaded application, if it isn't already. + // We need to let Foundation know that this is a multithreaded application, + // if it isn't already. if (![NSThread isMultiThreaded]) { - [NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil]; + [[[[NSThread alloc] init] autorelease] start]; } return JNI_VERSION_1_4; diff --git a/jdk/src/jdk.deploy.osx/macosx/native/libosx/CFileManager.m b/jdk/src/jdk.deploy.osx/macosx/native/libosx/CFileManager.m index f5e676ad490..52ca5f8eccf 100644 --- a/jdk/src/jdk.deploy.osx/macosx/native/libosx/CFileManager.m +++ b/jdk/src/jdk.deploy.osx/macosx/native/libosx/CFileManager.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, 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 @@ -213,25 +213,23 @@ JNF_COCOA_EXIT(env); */ JNIEXPORT jboolean JNICALL Java_com_apple_eio_FileManager__1moveToTrash -(JNIEnv *env, jclass clz, jstring url) +(JNIEnv *env, jclass clz, jstring fileName) { - __block jboolean returnValue = JNI_FALSE; + __block BOOL returnValue = NO; JNF_COCOA_ENTER(env); - NSString *path = JNFNormalizedNSStringForPath(env, url); + NSString * path = JNFNormalizedNSStringForPath(env, fileName); + NSURL *url = [NSURL fileURLWithPath:path]; [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - NSInteger res = 0; - [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation - source:[path stringByDeletingLastPathComponent] - destination:nil - files:[NSArray arrayWithObject:[path lastPathComponent]] - tag:&res]; - returnValue = (res == 0); + + returnValue = [[NSFileManager defaultManager] trashItemAtURL:url + resultingItemURL:nil + error:nil]; }]; JNF_COCOA_EXIT(env); - return returnValue; + return returnValue ? JNI_TRUE: JNI_FALSE; } /* From 43a028f60837bc5cd069eaf0dc446ac504d8ea86 Mon Sep 17 00:00:00 2001 From: Alexander Stepanov Date: Fri, 26 Feb 2016 19:24:06 +0300 Subject: [PATCH 083/183] 8150643: [TEST] add test for JDK-8150176 Reviewed-by: serb --- .../MultiResolutionTrayIconTest.html | 41 +++++++ .../MultiResolutionTrayIconTest.java | 116 ++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.html create mode 100644 jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java diff --git a/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.html b/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.html new file mode 100644 index 00000000000..7ff1134a69d --- /dev/null +++ b/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.html @@ -0,0 +1,41 @@ + + + + + MultiResolutionTrayIconTest + + + + +To run test please push "Start" (if system tray is not supported, push "Pass"). + +Two tray icons will appear (note: sometimes they can go to the tray icons pool). + +Please check if both of them have correct size and +the same colouring (white rectagle in a blue mount). In this case please push "Pass". + +Otherwise (if the 2nd red-white small icon appears) please push "Fail". + + + diff --git a/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java b/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java new file mode 100644 index 00000000000..f6f069b0ed8 --- /dev/null +++ b/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + @test + @bug 8150176 + @ignore 8150176 + @summary Check if correct resolution variant is used for tray icon. + @author a.stepanov + @run applet/manual=yesno MultiResolutionTrayIconTest.html +*/ + + +import java.applet.Applet; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.*; + + +public class MultiResolutionTrayIconTest extends Applet { + + private SystemTray tray; + private TrayIcon icon, iconMRI; + + public void init() { this.setLayout(new BorderLayout()); } + + public void start() { + + boolean trayIsSupported = SystemTray.isSupported(); + Button b = new Button("Start"); + if (trayIsSupported) { + + prepareIcons(); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { doTest(); } + }); + } else { + b.setLabel("not supported"); + b.setEnabled(false); + System.out.println("system tray is not supported"); + } + add(b, BorderLayout.CENTER); + + validate(); + setVisible(true); + } + + private BufferedImage generateImage(int w, int h, Color c) { + + BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + Graphics g = img.getGraphics(); + g.setColor(c); + g.fillRect(0, 0, w, h); + g.setColor(Color.WHITE); + int r = (Math.min(w, h) >= 8) ? 3 : 1; + g.fillRect(r, r, w - 2 * r, h - 2 * r); + return img; + } + + private void prepareIcons() { + + tray = SystemTray.getSystemTray(); + Dimension d = tray.getTrayIconSize(); + int w = d.width, h = d.height; + + BufferedImage img = generateImage(w, h, Color.BLUE); + // use wrong icon size for "nok" + BufferedImage nok = generateImage(w / 2 + 2, h / 2 + 2, Color.RED); + BaseMultiResolutionImage mri = + new BaseMultiResolutionImage(new BufferedImage[] {nok, img}); + icon = new TrayIcon(img); + iconMRI = new TrayIcon(mri); + } + + private void doTest() { + + if (tray.getTrayIcons().length > 0) { return; } // icons were added already + try { + tray.add(icon); + tray.add(iconMRI); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void stop() { + + // check for null, just in case + if (tray != null) { + tray.remove(icon); + tray.remove(iconMRI); + } + } +} From 6d7d3228e7b3fd1e3b4c2b51b8a7de6f04acdb0b Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Fri, 26 Feb 2016 09:13:22 -0800 Subject: [PATCH 084/183] 8147978: Remove Method::_method_data for C1 Method::_method_data field removed when not using C2 or JVMCI Reviewed-by: dholmes, kvn --- hotspot/src/share/vm/c1/c1_Runtime1.cpp | 26 ++++++++++++---------- hotspot/src/share/vm/oops/method.cpp | 5 +++-- hotspot/src/share/vm/oops/method.hpp | 18 +++++++++++++++ hotspot/src/share/vm/runtime/arguments.cpp | 6 +++++ hotspot/src/share/vm/runtime/vmStructs.cpp | 2 +- hotspot/src/share/vm/utilities/macros.hpp | 11 ++++++++- 6 files changed, 52 insertions(+), 16 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index 92c721575d0..01e639258c8 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -1502,21 +1502,23 @@ JRT_ENTRY(void, Runtime1::predicate_failed_trap(JavaThread* thread)) nm->make_not_entrant(); methodHandle m(nm->method()); - MethodData* mdo = m->method_data(); + if (ProfileInterpreter) { + MethodData* mdo = m->method_data(); - if (mdo == NULL && !HAS_PENDING_EXCEPTION) { - // Build an MDO. Ignore errors like OutOfMemory; - // that simply means we won't have an MDO to update. - Method::build_interpreter_method_data(m, THREAD); - if (HAS_PENDING_EXCEPTION) { - assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here"); - CLEAR_PENDING_EXCEPTION; + if (mdo == NULL && !HAS_PENDING_EXCEPTION) { + // Build an MDO. Ignore errors like OutOfMemory; + // that simply means we won't have an MDO to update. + Method::build_interpreter_method_data(m, THREAD); + if (HAS_PENDING_EXCEPTION) { + assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here"); + CLEAR_PENDING_EXCEPTION; + } + mdo = m->method_data(); } - mdo = m->method_data(); - } - if (mdo != NULL) { - mdo->inc_trap_count(Deoptimization::Reason_none); + if (mdo != NULL) { + mdo->inc_trap_count(Deoptimization::Reason_none); + } } if (TracePredicateFailedTraps) { diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 7620ea9f985..1f3eb751413 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -383,14 +383,15 @@ void Method::build_interpreter_method_data(const methodHandle& method, TRAPS) { MutexLocker ml(MethodData_lock, THREAD); if (method->method_data() == NULL) { ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); +#if defined(COMPILER2) || INCLUDE_JVMCI MethodData* method_data = MethodData::allocate(loader_data, method, THREAD); if (HAS_PENDING_EXCEPTION) { CompileBroker::log_metaspace_failure(); ClassLoaderDataGraph::set_metaspace_oom(true); return; // return the exception (which is cleared) } - method->set_method_data(method_data); +#endif if (PrintMethodData && (Verbose || WizardMode)) { ResourceMark rm(THREAD); tty->print("build_interpreter_method_data for "); @@ -920,7 +921,7 @@ void Method::unlink_method() { // shared class that failed to load, this->link_method() may // have already been called (before an exception happened), so // this->_method_data may not be NULL. - assert(!DumpSharedSpaces || _method_data == NULL, "unexpected method data?"); + assert(!DumpSharedSpaces || method_data() == NULL, "unexpected method data?"); set_method_data(NULL); clear_method_counters(); diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 8fc7b133a16..fdf7d1f9fb0 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -64,7 +64,9 @@ class Method : public Metadata { friend class JVMCIVMStructs; private: ConstMethod* _constMethod; // Method read-only data. +#if defined(COMPILER2) || INCLUDE_JVMCI MethodData* _method_data; +#endif MethodCounters* _method_counters; AccessFlags _access_flags; // Access flags int _vtable_index; // vtable index of this method (see VtableIndexFlag) @@ -319,6 +321,7 @@ class Method : public Metadata { // InterpreterRuntime::exception_handler_for_exception. static int fast_exception_handler_bci_for(methodHandle mh, KlassHandle ex_klass, int throw_bci, TRAPS); +#if defined(COMPILER2) || INCLUDE_JVMCI // method data access MethodData* method_data() const { return _method_data; @@ -330,6 +333,10 @@ class Method : public Metadata { // the initialization of data otherwise. OrderAccess::release_store_ptr((volatile void *)&_method_data, data); } +#else + MethodData* method_data() const { return NULL; } + void set_method_data(MethodData* data) { } +#endif MethodCounters* method_counters() const { return _method_counters; @@ -639,9 +646,16 @@ class Method : public Metadata { #endif /* CC_INTERP */ static ByteSize from_compiled_offset() { return byte_offset_of(Method, _from_compiled_entry); } static ByteSize code_offset() { return byte_offset_of(Method, _code); } +#if defined(COMPILER2) || INCLUDE_JVMCI static ByteSize method_data_offset() { return byte_offset_of(Method, _method_data); } +#else + static ByteSize method_data_offset() { + ShouldNotReachHere(); + return in_ByteSize(0); + } +#endif static ByteSize method_counters_offset() { return byte_offset_of(Method, _method_counters); } @@ -654,7 +668,11 @@ class Method : public Metadata { static ByteSize signature_handler_offset() { return in_ByteSize(sizeof(Method) + wordSize); } // for code generation +#if defined(COMPILER2) || INCLUDE_JVMCI static int method_data_offset_in_bytes() { return offset_of(Method, _method_data); } +#else + static int method_data_offset_in_bytes() { ShouldNotReachHere(); return 0; } +#endif static int intrinsic_id_offset_in_bytes() { return offset_of(Method, _intrinsic_id); } static int intrinsic_id_size_in_bytes() { return sizeof(u2); } diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 006e3c94739..ca25748543e 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -3464,6 +3464,12 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req } #endif +#if !defined(COMPILER2) && !INCLUDE_JVMCI + UNSUPPORTED_OPTION(ProfileInterpreter, "ProfileInterpreter"); + NOT_PRODUCT(UNSUPPORTED_OPTION(TraceProfileInterpreter, "TraceProfileInterpreter")); + UNSUPPORTED_OPTION(PrintMethodData, "PrintMethodData"); +#endif + #ifndef TIERED // Tiered compilation is undefined. UNSUPPORTED_OPTION(TieredCompilation, "TieredCompilation"); diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 84d2c6ebd3b..6630da1633c 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -390,7 +390,7 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(MethodCounters, _invocation_counter, InvocationCounter) \ nonstatic_field(MethodCounters, _backedge_counter, InvocationCounter) \ nonstatic_field(Method, _constMethod, ConstMethod*) \ - nonstatic_field(Method, _method_data, MethodData*) \ + COMPILER2_OR_JVMCI_PRESENT(nonstatic_field(Method, _method_data, MethodData*)) \ nonstatic_field(Method, _method_counters, MethodCounters*) \ nonstatic_field(Method, _access_flags, AccessFlags) \ nonstatic_field(Method, _vtable_index, int) \ diff --git a/hotspot/src/share/vm/utilities/macros.hpp b/hotspot/src/share/vm/utilities/macros.hpp index ccdb90813b7..11b4fe4f3aa 100644 --- a/hotspot/src/share/vm/utilities/macros.hpp +++ b/hotspot/src/share/vm/utilities/macros.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -206,6 +206,15 @@ #define NOT_COMPILER2(code) code #endif // COMPILER2 +// COMPILER2 or JVMCI +#if defined(COMPILER2) || INCLUDE_JVMCI +#define COMPILER2_OR_JVMCI_PRESENT(code) code +#define NOT_COMPILER2_OR_JVMCI(code) +#else +#define COMPILER2_OR_JVMCI_PRESENT(code) +#define NOT_COMPILER2_OR_JVMCI(code) code +#endif + #ifdef TIERED #define TIERED_ONLY(code) code #define NOT_TIERED(code) From 41c0116f6ef2f0e1e12de4909b5e56a4662d51fd Mon Sep 17 00:00:00 2001 From: Joseph Provino Date: Fri, 26 Feb 2016 14:02:39 -0500 Subject: [PATCH 085/183] 8139651: ConcurrentG1Refine uses ints for many of its members that should be unsigned types Ints need to be changed to size_t Reviewed-by: kbarrett, tbenson --- .../src/share/vm/gc/g1/concurrentG1Refine.cpp | 8 +++---- .../src/share/vm/gc/g1/concurrentG1Refine.hpp | 24 +++++++++---------- .../vm/gc/g1/concurrentG1RefineThread.cpp | 12 ++++++---- .../vm/gc/g1/concurrentG1RefineThread.hpp | 8 +++---- hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp | 14 ++++++----- hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp | 4 ++-- .../src/share/vm/gc/g1/g1CollectedHeap.cpp | 4 ++-- .../src/share/vm/gc/g1/g1CollectorPolicy.cpp | 16 ++++++------- .../src/share/vm/gc/g1/g1ConcurrentMark.cpp | 4 ++-- hotspot/src/share/vm/gc/g1/g1RemSet.cpp | 1 - hotspot/src/share/vm/gc/g1/g1_globals.hpp | 22 ++++++++--------- hotspot/src/share/vm/gc/g1/ptrQueue.cpp | 12 ++++++---- hotspot/src/share/vm/gc/g1/ptrQueue.hpp | 12 +++++----- 13 files changed, 73 insertions(+), 68 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp index 0e2f4dd4bb3..5edec2775ed 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, 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 @@ -36,19 +36,19 @@ ConcurrentG1Refine::ConcurrentG1Refine(G1CollectedHeap* g1h) : { // Ergonomically select initial concurrent refinement parameters if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) { - FLAG_SET_DEFAULT(G1ConcRefinementGreenZone, (intx)ParallelGCThreads); + FLAG_SET_DEFAULT(G1ConcRefinementGreenZone, ParallelGCThreads); } set_green_zone(G1ConcRefinementGreenZone); if (FLAG_IS_DEFAULT(G1ConcRefinementYellowZone)) { FLAG_SET_DEFAULT(G1ConcRefinementYellowZone, green_zone() * 3); } - set_yellow_zone(MAX2(G1ConcRefinementYellowZone, green_zone())); + set_yellow_zone(MAX2(G1ConcRefinementYellowZone, green_zone())); if (FLAG_IS_DEFAULT(G1ConcRefinementRedZone)) { FLAG_SET_DEFAULT(G1ConcRefinementRedZone, yellow_zone() * 2); } - set_red_zone(MAX2(G1ConcRefinementRedZone, yellow_zone())); + set_red_zone(MAX2(G1ConcRefinementRedZone, yellow_zone())); } ConcurrentG1Refine* ConcurrentG1Refine::create(G1CollectedHeap* g1h, CardTableEntryClosure* refine_closure, jint* ecode) { diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp index 0e5525f73c2..2333fea311f 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, 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 @@ -61,11 +61,11 @@ class ConcurrentG1Refine: public CHeapObj { * 2) green = 0. Means no caching. Can be a good way to minimize the * amount of time spent updating rsets during a collection. */ - int _green_zone; - int _yellow_zone; - int _red_zone; + size_t _green_zone; + size_t _yellow_zone; + size_t _red_zone; - int _thread_threshold_step; + size_t _thread_threshold_step; // We delay the refinement of 'hot' cards using the hot card cache. G1HotCardCache _hot_card_cache; @@ -100,17 +100,17 @@ class ConcurrentG1Refine: public CHeapObj { void print_worker_threads_on(outputStream* st) const; - void set_green_zone(int x) { _green_zone = x; } - void set_yellow_zone(int x) { _yellow_zone = x; } - void set_red_zone(int x) { _red_zone = x; } + void set_green_zone(size_t x) { _green_zone = x; } + void set_yellow_zone(size_t x) { _yellow_zone = x; } + void set_red_zone(size_t x) { _red_zone = x; } - int green_zone() const { return _green_zone; } - int yellow_zone() const { return _yellow_zone; } - int red_zone() const { return _red_zone; } + size_t green_zone() const { return _green_zone; } + size_t yellow_zone() const { return _yellow_zone; } + size_t red_zone() const { return _red_zone; } uint worker_thread_num() const { return _n_worker_threads; } - int thread_threshold_step() const { return _thread_threshold_step; } + size_t thread_threshold_step() const { return _thread_threshold_step; } G1HotCardCache* hot_card_cache() { return &_hot_card_cache; } diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp index cefcab3065b..1e8081e53e0 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp @@ -67,10 +67,12 @@ ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *nex void ConcurrentG1RefineThread::initialize() { // Current thread activation threshold - _threshold = MIN2(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(), + _threshold = MIN2(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(), cg1r()->yellow_zone()); // A thread deactivates once the number of buffer reached a deactivation threshold - _deactivation_threshold = MAX2(_threshold - cg1r()->thread_threshold_step(), cg1r()->green_zone()); + _deactivation_threshold = + MAX2(_threshold - MIN2(_threshold, cg1r()->thread_threshold_step()), + cg1r()->green_zone()); } void ConcurrentG1RefineThread::wait_for_completed_buffers() { @@ -127,14 +129,14 @@ void ConcurrentG1RefineThread::run_service() { } DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); - log_debug(gc, refine)("Activated %d, on threshold: %d, current: %d", + log_debug(gc, refine)("Activated %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT, _worker_id, _threshold, dcqs.completed_buffers_num()); { SuspendibleThreadSetJoiner sts_join; do { - int curr_buffer_num = (int)dcqs.completed_buffers_num(); + size_t curr_buffer_num = dcqs.completed_buffers_num(); // If the number of the buffers falls down into the yellow zone, // that means that the transition period after the evacuation pause has ended. if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) { @@ -151,7 +153,7 @@ void ConcurrentG1RefineThread::run_service() { false /* during_pause */)); deactivate(); - log_debug(gc, refine)("Deactivated %d, off threshold: %d, current: %d", + log_debug(gc, refine)("Deactivated %d, off threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT, _worker_id, _deactivation_threshold, dcqs.completed_buffers_num()); } diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp index 5b6d3ed79d5..40071766d6f 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, 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 @@ -53,11 +53,11 @@ class ConcurrentG1RefineThread: public ConcurrentGCThread { // The closure applied to completed log buffers. CardTableEntryClosure* _refine_closure; - int _thread_threshold_step; + size_t _thread_threshold_step; // This thread activation threshold - int _threshold; + size_t _threshold; // This thread deactivation threshold - int _deactivation_threshold; + size_t _deactivation_threshold; void wait_for_completed_buffers(); diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp index 4c33fb9b211..d79ac8066b9 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp @@ -207,22 +207,24 @@ bool DirtyCardQueueSet::mut_process_buffer(void** buf) { } -BufferNode* DirtyCardQueueSet::get_completed_buffer(int stop_at) { +BufferNode* DirtyCardQueueSet::get_completed_buffer(size_t stop_at) { BufferNode* nd = NULL; MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); - if ((int)_n_completed_buffers <= stop_at) { + if (_n_completed_buffers <= stop_at) { _process_completed = false; return NULL; } if (_completed_buffers_head != NULL) { nd = _completed_buffers_head; + assert(_n_completed_buffers > 0, "Invariant"); _completed_buffers_head = nd->next(); - if (_completed_buffers_head == NULL) - _completed_buffers_tail = NULL; _n_completed_buffers--; - assert(_n_completed_buffers >= 0, "Invariant"); + if (_completed_buffers_head == NULL) { + assert(_n_completed_buffers == 0, "Invariant"); + _completed_buffers_tail = NULL; + } } DEBUG_ONLY(assert_completed_buffer_list_len_correct_locked()); return nd; @@ -230,7 +232,7 @@ BufferNode* DirtyCardQueueSet::get_completed_buffer(int stop_at) { bool DirtyCardQueueSet::apply_closure_to_completed_buffer(CardTableEntryClosure* cl, uint worker_i, - int stop_at, + size_t stop_at, bool during_pause) { assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause"); BufferNode* nd = get_completed_buffer(stop_at); diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp index 17c92bb8ecf..96865a5784b 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp @@ -134,10 +134,10 @@ public: // is returned to the completed buffer set, and this call returns false. bool apply_closure_to_completed_buffer(CardTableEntryClosure* cl, uint worker_i, - int stop_at, + size_t stop_at, bool during_pause); - BufferNode* get_completed_buffer(int stop_at); + BufferNode* get_completed_buffer(size_t stop_at); // Applies the current closure to all completed buffers, // non-consumptively. diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index be30e88c541..01907547340 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -1984,8 +1984,8 @@ jint G1CollectedHeap::initialize() { JavaThread::dirty_card_queue_set().initialize(_refine_cte_cl, DirtyCardQ_CBL_mon, DirtyCardQ_FL_lock, - concurrent_g1_refine()->yellow_zone(), - concurrent_g1_refine()->red_zone(), + (int)concurrent_g1_refine()->yellow_zone(), + (int)concurrent_g1_refine()->red_zone(), Shared_DirtyCardQ_lock, NULL, // fl_owner true); // init_free_ids diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index f14e360ce44..bd98877eded 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -1301,12 +1301,12 @@ void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time, const int k_gy = 3, k_gr = 6; const double inc_k = 1.1, dec_k = 0.9; - int g = cg1r->green_zone(); + size_t g = cg1r->green_zone(); if (update_rs_time > goal_ms) { - g = (int)(g * dec_k); // Can become 0, that's OK. That would mean a mutator-only processing. + g = (size_t)(g * dec_k); // Can become 0, that's OK. That would mean a mutator-only processing. } else { if (update_rs_time < goal_ms && update_rs_processed_buffers > g) { - g = (int)MAX2(g * inc_k, g + 1.0); + g = (size_t)MAX2(g * inc_k, g + 1.0); } } // Change the refinement threads params @@ -1315,15 +1315,15 @@ void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time, cg1r->set_red_zone(g * k_gr); cg1r->reinitialize_threads(); - int processing_threshold_delta = MAX2((int)(cg1r->green_zone() * _predictor.sigma()), 1); - int processing_threshold = MIN2(cg1r->green_zone() + processing_threshold_delta, + size_t processing_threshold_delta = MAX2(cg1r->green_zone() * _predictor.sigma(), 1); + size_t processing_threshold = MIN2(cg1r->green_zone() + processing_threshold_delta, cg1r->yellow_zone()); // Change the barrier params - dcqs.set_process_completed_threshold(processing_threshold); - dcqs.set_max_completed_queue(cg1r->red_zone()); + dcqs.set_process_completed_threshold((int)processing_threshold); + dcqs.set_max_completed_queue((int)cg1r->red_zone()); } - int curr_queue_size = dcqs.completed_buffers_num(); + size_t curr_queue_size = dcqs.completed_buffers_num(); if (curr_queue_size >= cg1r->yellow_zone()) { dcqs.set_completed_queue_padding(curr_queue_size); } else { diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp index edfb510d6fe..6605b0cf621 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, 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 @@ -2271,7 +2271,7 @@ void G1ConcurrentMark::checkpointRootsFinalWork() { SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); guarantee(has_overflown() || satb_mq_set.completed_buffers_num() == 0, - "Invariant: has_overflown = %s, num buffers = %d", + "Invariant: has_overflown = %s, num buffers = " SIZE_FORMAT, BOOL_TO_STR(has_overflown()), satb_mq_set.completed_buffers_num()); diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp index 40e3959c886..3d2917a2184 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp @@ -291,7 +291,6 @@ void G1RemSet::cleanup_after_oops_into_collection_set_do() { _g1->cleanUpCardTable(); DirtyCardQueueSet& into_cset_dcqs = _into_cset_dirty_card_queue_set; - int into_cset_n_buffers = into_cset_dcqs.completed_buffers_num(); if (_g1->evacuation_failed()) { double restore_remembered_set_start = os::elapsedTime(); diff --git a/hotspot/src/share/vm/gc/g1/g1_globals.hpp b/hotspot/src/share/vm/gc/g1/g1_globals.hpp index 086e27bd589..370ba86eb09 100644 --- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, 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 @@ -107,35 +107,35 @@ "Size of an update buffer") \ range(1, NOT_LP64(32*M) LP64_ONLY(1*G)) \ \ - product(intx, G1ConcRefinementYellowZone, 0, \ + product(size_t, G1ConcRefinementYellowZone, 0, \ "Number of enqueued update buffers that will " \ "trigger concurrent processing. Will be selected ergonomically " \ "by default.") \ - range(0, max_intx) \ + range(0, SIZE_MAX) \ \ - product(intx, G1ConcRefinementRedZone, 0, \ + product(size_t, G1ConcRefinementRedZone, 0, \ "Maximum number of enqueued update buffers before mutator " \ "threads start processing new ones instead of enqueueing them. " \ "Will be selected ergonomically by default. Zero will disable " \ "concurrent processing.") \ - range(0, max_intx) \ + range(0, SIZE_MAX) \ \ - product(intx, G1ConcRefinementGreenZone, 0, \ + product(size_t, G1ConcRefinementGreenZone, 0, \ "The number of update buffers that are left in the queue by the " \ "concurrent processing threads. Will be selected ergonomically " \ "by default.") \ - range(0, max_intx) \ + range(0, SIZE_MAX) \ \ - product(intx, G1ConcRefinementServiceIntervalMillis, 300, \ + product(uintx, G1ConcRefinementServiceIntervalMillis, 300, \ "The last concurrent refinement thread wakes up every " \ "specified number of milliseconds to do miscellaneous work.") \ - range(0, max_jint) \ + range(0, max_uintx) \ \ - product(intx, G1ConcRefinementThresholdStep, 0, \ + product(size_t, G1ConcRefinementThresholdStep, 0, \ "Each time the rset update queue increases by this amount " \ "activate the next refinement thread if available. " \ "Will be selected ergonomically by default.") \ - range(0, max_jint) \ + range(0, SIZE_MAX) \ \ product(intx, G1RSetUpdatingPauseTimePercent, 10, \ "A target percentage of time that is allowed to be spend on " \ diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp index 55b41a0b605..d6cf5c50e6a 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp @@ -271,16 +271,17 @@ void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) { _n_completed_buffers++; if (!_process_completed && _process_completed_threshold >= 0 && - _n_completed_buffers >= _process_completed_threshold) { + _n_completed_buffers >= (size_t)_process_completed_threshold) { _process_completed = true; - if (_notify_when_complete) + if (_notify_when_complete) { _cbl_mon->notify(); + } } DEBUG_ONLY(assert_completed_buffer_list_len_correct_locked()); } -int PtrQueueSet::completed_buffers_list_length() { - int n = 0; +size_t PtrQueueSet::completed_buffers_list_length() { + size_t n = 0; BufferNode* cbn = _completed_buffers_head; while (cbn != NULL) { n++; @@ -334,7 +335,8 @@ void PtrQueueSet::merge_bufferlists(PtrQueueSet *src) { void PtrQueueSet::notify_if_necessary() { MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); - if (_n_completed_buffers >= _process_completed_threshold || _max_completed_queue == 0) { + assert(_process_completed_threshold >= 0, "_process_completed is negative"); + if (_n_completed_buffers >= (size_t)_process_completed_threshold || _max_completed_queue == 0) { _process_completed = true; if (_notify_when_complete) _cbl_mon->notify(); diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp index a2207641238..4d5c5e6c28a 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp @@ -209,7 +209,7 @@ protected: Monitor* _cbl_mon; // Protects the fields below. BufferNode* _completed_buffers_head; BufferNode* _completed_buffers_tail; - int _n_completed_buffers; + size_t _n_completed_buffers; int _process_completed_threshold; volatile bool _process_completed; @@ -233,9 +233,9 @@ protected: // Maximum number of elements allowed on completed queue: after that, // enqueuer does the work itself. Zero indicates no maximum. int _max_completed_queue; - int _completed_queue_padding; + size_t _completed_queue_padding; - int completed_buffers_list_length(); + size_t completed_buffers_list_length(); void assert_completed_buffer_list_len_correct_locked(); void assert_completed_buffer_list_len_correct(); @@ -299,15 +299,15 @@ public: // list size may be reduced, if that is deemed desirable. void reduce_free_list(); - int completed_buffers_num() { return _n_completed_buffers; } + size_t completed_buffers_num() { return _n_completed_buffers; } void merge_bufferlists(PtrQueueSet* src); void set_max_completed_queue(int m) { _max_completed_queue = m; } int max_completed_queue() { return _max_completed_queue; } - void set_completed_queue_padding(int padding) { _completed_queue_padding = padding; } - int completed_queue_padding() { return _completed_queue_padding; } + void set_completed_queue_padding(size_t padding) { _completed_queue_padding = padding; } + size_t completed_queue_padding() { return _completed_queue_padding; } // Notify the consumer if the number of buffers crossed the threshold void notify_if_necessary(); From 234373ff31ee35fb5cad93317baa30b26fa6edbe Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Sun, 28 Feb 2016 12:22:05 -0500 Subject: [PATCH 086/183] 8150421: Delete experimental G1UseConcMarkReferenceProcessing Removed the option and supporting code. Reviewed-by: jmasa, tamao --- hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp | 7 ++----- hotspot/src/share/vm/gc/g1/g1_globals.hpp | 4 ---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp index 6605b0cf621..5ece63cea5d 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp @@ -2702,11 +2702,8 @@ public: }; static ReferenceProcessor* get_cm_oop_closure_ref_processor(G1CollectedHeap* g1h) { - ReferenceProcessor* result = NULL; - if (G1UseConcMarkReferenceProcessing) { - result = g1h->ref_processor_cm(); - assert(result != NULL, "should not be NULL"); - } + ReferenceProcessor* result = g1h->ref_processor_cm(); + assert(result != NULL, "CM reference processor should not be NULL"); return result; } diff --git a/hotspot/src/share/vm/gc/g1/g1_globals.hpp b/hotspot/src/share/vm/gc/g1/g1_globals.hpp index 370ba86eb09..fa210295098 100644 --- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp @@ -71,10 +71,6 @@ "draining concurrent marking work queues.") \ range(1, max_intx) \ \ - experimental(bool, G1UseConcMarkReferenceProcessing, true, \ - "If true, enable reference discovery during concurrent " \ - "marking and reference processing at the end of remark.") \ - \ experimental(double, G1LastPLABAverageOccupancy, 50.0, \ "The expected average occupancy of the last PLAB in " \ "percent.") \ From 31f86a2308104bcbf173193ee988c25ece2ec05e Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 29 Feb 2016 08:50:57 +0100 Subject: [PATCH 087/183] 8150619: Improve thread based logging introduced with 8149036 Reviewed-by: coleenp, dholmes --- hotspot/src/os/aix/vm/os_aix.cpp | 18 ++--- hotspot/src/os/bsd/vm/os_bsd.cpp | 6 +- hotspot/src/os/linux/vm/os_linux.cpp | 2 +- hotspot/src/os/solaris/vm/os_solaris.cpp | 9 ++- hotspot/src/os/windows/vm/os_windows.cpp | 5 +- hotspot/src/share/vm/runtime/thread.cpp | 8 +-- .../runtime/logging/ThreadLoggingTest.java | 69 +++++++++++++++++++ 7 files changed, 92 insertions(+), 25 deletions(-) create mode 100644 hotspot/test/runtime/logging/ThreadLoggingTest.java diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index c38d2a3fbd0..2193a9611a3 100644 --- a/hotspot/src/os/aix/vm/os_aix.cpp +++ b/hotspot/src/os/aix/vm/os_aix.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 SAP SE. 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 @@ -792,8 +792,8 @@ static void *java_start(Thread *thread) { const pthread_t pthread_id = ::pthread_self(); const tid_t kernel_thread_id = ::thread_self(); - log_info(os, thread)("Thread is alive (pthread id " UINTX_FORMAT ", tid " UINTX_FORMAT ")", - (uintx) pthread_id, (uintx) kernel_thread_id); + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", kernel thread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) kernel_thread_id); // Normally, pthread stacks on AIX live in the data segment (are allocated with malloc() // by the pthread library). In rare cases, this may not be the case, e.g. when third-party @@ -801,7 +801,7 @@ static void *java_start(Thread *thread) { // guard pages on those stacks, because the stacks may reside in memory which is not // protectable (shmated). if (thread->stack_base() > ::sbrk(0)) { - log_warning(os, thread)("Thread " UINTX_FORMAT ": stack not in data segment.", (uintx)pthread_id); + log_warning(os, thread)("Thread stack not in data segment."); } // Try to randomize the cache line index of hot stack frames. @@ -835,8 +835,8 @@ static void *java_start(Thread *thread) { // Call one more level start routine. thread->run(); - log_info(os, thread)("Thread finished (pthread id " UINTX_FORMAT ", tid " UINTX_FORMAT ").", - (uintx) pthread_id, (uintx) kernel_thread_id); + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ", kernel thread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) kernel_thread_id); return 0; } @@ -978,8 +978,8 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Aix::hotspot_sigmask(thread); - log_info(os, thread)("Thread attached (pthread id " UINTX_FORMAT ", tid " UINTX_FORMAT ")", - (uintx) pthread_id, (uintx) kernel_thread_id); + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", kernel thread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) kernel_thread_id); return true; } diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 51fce416eda..3d6f8fd6422 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -682,7 +682,7 @@ static void *java_start(Thread *thread) { osthread->set_thread_id(os::Bsd::gettid()); - log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ".", + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", os::current_thread_id(), (uintx) pthread_self()); #ifdef __APPLE__ @@ -720,7 +720,7 @@ static void *java_start(Thread *thread) { // call one more level start routine thread->run(); - log_info(os, thread)("Thread finished (tid " UINTX_FORMAT ", pthread id " UINTX_FORMAT ").", + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", os::current_thread_id(), (uintx) pthread_self()); return 0; @@ -871,7 +871,7 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Bsd::hotspot_sigmask(thread); - log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ".", + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", os::current_thread_id(), (uintx) pthread_self()); return true; diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 5bf366d3997..d46a1146dd7 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -694,7 +694,7 @@ static void *java_start(Thread *thread) { // call one more level start routine thread->run(); - log_info(os, thread)("Thread finished (tid " UINTX_FORMAT ", pthread id " UINTX_FORMAT ").", + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", os::current_thread_id(), (uintx) pthread_self()); return 0; diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index e454ed165c7..bc8138db6ff 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, 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 @@ -891,12 +891,11 @@ bool os::create_main_thread(JavaThread* thread) { // Helper function to trace thread attributes, similar to os::Posix::describe_pthread_attr() static char* describe_thr_create_attributes(char* buf, size_t buflen, - size_t stacksize, long flags) -{ + size_t stacksize, long flags) { stringStream ss(buf, buflen); ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024); ss.print("flags: "); - #define PRINT_FLAG(f) if (flags & f) ss.print( XSTR(f) " "); + #define PRINT_FLAG(f) if (flags & f) ss.print( #f " "); #define ALL(X) \ X(THR_SUSPENDED) \ X(THR_DETACHED) \ @@ -1006,7 +1005,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, char buf[64]; if (status == 0) { - log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + log_info(os, thread)("Thread started (tid: " UINTX_FORMAT ", attributes: %s). ", (uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); } else { log_warning(os, thread)("Failed to start thread - thr_create failed (%s) for attributes: %s.", diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 7b371739e09..f8bc6081d8b 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -543,8 +543,7 @@ bool os::create_main_thread(JavaThread* thread) { // Helper function to trace _beginthreadex attributes, // similar to os::Posix::describe_pthread_attr() static char* describe_beginthreadex_attributes(char* buf, size_t buflen, - size_t stacksize, unsigned initflag) -{ + size_t stacksize, unsigned initflag) { stringStream ss(buf, buflen); if (stacksize == 0) { ss.print("stacksize: default, "); @@ -552,7 +551,7 @@ static char* describe_beginthreadex_attributes(char* buf, size_t buflen, ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024); } ss.print("flags: "); - #define PRINT_FLAG(f) if (initflag & f) ss.print( XSTR(f) " "); + #define PRINT_FLAG(f) if (initflag & f) ss.print( #f " "); #define ALL(X) \ X(CREATE_SUSPENDED) \ X(STACK_SIZE_PARAM_IS_A_RESERVATION) diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 654aebd9e70..8e1e997f8c1 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -1806,10 +1806,6 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { // Call after last event on thread EVENT_THREAD_EXIT(this); - log_info(os, thread)("Thread " UINTX_FORMAT " %s.", - os::current_thread_id(), - exit_type == JavaThread::normal_exit ? "exiting" : "detaching"); - // Call Thread.exit(). We try 3 times in case we got another Thread.stop during // the execution of the method. If that is not enough, then we don't really care. Thread.stop // is deprecated anyhow. @@ -1932,6 +1928,10 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { } #endif // INCLUDE_ALL_GCS + log_info(os, thread)("JavaThread %s (tid: " UINTX_FORMAT ").", + exit_type == JavaThread::normal_exit ? "exiting" : "detaching", + os::current_thread_id()); + // Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread Threads::remove(this); } diff --git a/hotspot/test/runtime/logging/ThreadLoggingTest.java b/hotspot/test/runtime/logging/ThreadLoggingTest.java new file mode 100644 index 00000000000..a5cde9c845c --- /dev/null +++ b/hotspot/test/runtime/logging/ThreadLoggingTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, SAP SE and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8149036 8150619 + * @summary os+thread output should contain logging calls for thread start stop attaches detaches + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools + * @run driver ThreadLoggingTest + * @author Thomas Stuefe (SAP) + */ + +import java.io.File; +import java.util.Map; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +public class ThreadLoggingTest { + + static void analyzeOutputForInfoLevel(OutputAnalyzer output) throws Exception { + output.shouldContain("Thread started"); + output.shouldContain("Thread is alive"); + output.shouldContain("Thread finished"); + output.shouldHaveExitValue(0); + } + + static void analyzeOutputForDebugLevel(OutputAnalyzer output) throws Exception { + analyzeOutputForInfoLevel(output); + output.shouldContain("stack dimensions"); + output.shouldContain("stack guard pages"); + } + + public static void main(String[] args) throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:os+thread", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + analyzeOutputForInfoLevel(output); + + pb = ProcessTools.createJavaProcessBuilder("-Xlog:os+thread=debug", "-version"); + output = new OutputAnalyzer(pb.start()); + analyzeOutputForDebugLevel(output); + + } + +} From 98fc723fbf46d4da77782316a67d3fbd3a7dcf91 Mon Sep 17 00:00:00 2001 From: Prem Balakrishnan Date: Mon, 29 Feb 2016 14:19:40 +0530 Subject: [PATCH 088/183] 7126823: JInternalFrame.getNormalBounds() returns bad value after iconify/deiconify Reviewed-by: ssadetsky, rchamyal --- .../javax/swing/DefaultDesktopManager.java | 6 - .../swing/plaf/synth/SynthDesktopPaneUI.java | 3 - .../JInternalFrame/NormalBoundsTest.java | 301 ++++++++++++++++++ 3 files changed, 301 insertions(+), 9 deletions(-) create mode 100644 jdk/test/javax/swing/JInternalFrame/NormalBoundsTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/DefaultDesktopManager.java b/jdk/src/java.desktop/share/classes/javax/swing/DefaultDesktopManager.java index 18f30579f4e..74778d50267 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/DefaultDesktopManager.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/DefaultDesktopManager.java @@ -191,12 +191,6 @@ public class DefaultDesktopManager implements DesktopManager, java.io.Serializab JLayeredPane.putLayer(desktopIcon, layer); } - // If we are maximized we already have the normal bounds recorded - // don't try to re-record them, otherwise we incorrectly set the - // normal bounds to maximized state. - if (!f.isMaximum()) { - f.setNormalBounds(f.getBounds()); - } if (findNext) { if (d.selectFrame(true) == null) { // The icon is the last frame. diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopPaneUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopPaneUI.java index b22941c8f6f..f7b370eb35b 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopPaneUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopPaneUI.java @@ -362,9 +362,6 @@ public class SynthDesktopPaneUI extends BasicDesktopPaneUI implements setWasIcon(f, Boolean.TRUE); } - if (!f.isMaximum()) { - f.setNormalBounds(f.getBounds()); - } c.remove(f); c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight()); try { diff --git a/jdk/test/javax/swing/JInternalFrame/NormalBoundsTest.java b/jdk/test/javax/swing/JInternalFrame/NormalBoundsTest.java new file mode 100644 index 00000000000..2a6d7f998a9 --- /dev/null +++ b/jdk/test/javax/swing/JInternalFrame/NormalBoundsTest.java @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + @test + @bug 7126823 + @summary Verify NormalBounds upon iconify/deiconify sequence + @run main NormalBoundsTest + */ +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.beans.PropertyVetoException; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.WindowConstants; + +public class NormalBoundsTest { + + private static JFrame mainFrame; + private static JInternalFrame internalFrame; + private static Rectangle bounds; + + private static void createUI(String lookAndFeelString) { + internalFrame = new JInternalFrame("Internal", true, true, true, true); + internalFrame.setDefaultCloseOperation( + WindowConstants.DO_NOTHING_ON_CLOSE); + internalFrame.setSize(200, 200); + + JDesktopPane desktopPane = new JDesktopPane(); + desktopPane.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); + desktopPane.add(internalFrame); + + mainFrame = new JFrame(lookAndFeelString); + mainFrame.setSize(640, 480); + mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + mainFrame.setContentPane(desktopPane); + + mainFrame.setVisible(true); + internalFrame.setVisible(true); + + } + + private static int signWOZero(int i) { + return (i > 0) ? 1 : -1; + } + + private static void mouseMove(Robot robot, Point startPt, Point endPt) { + int dx = endPt.x - startPt.x; + int dy = endPt.y - startPt.y; + + int ax = Math.abs(dx) * 2; + int ay = Math.abs(dy) * 2; + + int sx = signWOZero(dx); + int sy = signWOZero(dy); + + int x = startPt.x; + int y = startPt.y; + + int d = 0; + + if (ax > ay) { + d = ay - ax / 2; + while (true) { + robot.mouseMove(x, y); + robot.delay(50); + + if (x == endPt.x) { + return; + } + if (d >= 0) { + y = y + sy; + d = d - ax; + } + x = x + sx; + d = d + ay; + } + } else { + d = ax - ay / 2; + while (true) { + robot.mouseMove(x, y); + robot.delay(50); + + if (y == endPt.y) { + return; + } + if (d >= 0) { + x = x + sx; + d = d - ay; + } + y = y + sy; + d = d + ax; + } + } + } + + private static void drag(Robot r, Point startPt, Point endPt, int button) { + if (!(button == InputEvent.BUTTON1_MASK + || button == InputEvent.BUTTON2_MASK + || button == InputEvent.BUTTON3_MASK)) { + throw new IllegalArgumentException("invalid mouse button"); + } + + r.mouseMove(startPt.x, startPt.y); + r.mousePress(button); + try { + mouseMove(r, startPt, endPt); + } finally { + r.mouseRelease(button); + } + } + + private static boolean tryLookAndFeel(String lookAndFeelString) { + try { + UIManager.setLookAndFeel(lookAndFeelString); + return true; + } catch (UnsupportedLookAndFeelException | ClassNotFoundException | + InstantiationException | IllegalAccessException e) { + return false; + } + } + + public static void executeTest(Robot robot) throws Exception { + + // Iconize JInternalFrame + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + internalFrame.setIcon(true); + } catch (PropertyVetoException ex) { + mainFrame.dispose(); + throw new RuntimeException("Iconize InternalFrame Failed"); + } + } + }); + robot.waitForIdle(); + + // Deiconize JInternalFrame + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + internalFrame.setIcon(false); + } catch (PropertyVetoException ex) { + mainFrame.dispose(); + throw new RuntimeException("Deiconize InternalFrame" + + " Failed"); + } + } + }); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + Point loc = internalFrame.getLocationOnScreen(); + // Drag Frame + drag(robot, + new Point((int) loc.x + 80, (int) loc.y + 12), + new Point((int) loc.x + 100, (int) loc.y + 40), + InputEvent.BUTTON1_MASK); + } + }); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + bounds = internalFrame.getBounds(); + if (!internalFrame.getNormalBounds().equals(bounds)) { + mainFrame.dispose(); + throw new RuntimeException("Invalid NormalBounds"); + } + } + }); + robot.waitForIdle(); + + // Regression Test Bug ID: 4424247 + // Maximize JInternalFrame + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + internalFrame.setMaximum(true); + } catch (PropertyVetoException ex) { + mainFrame.dispose(); + throw new RuntimeException("Maximize InternalFrame Failed"); + } + } + }); + robot.waitForIdle(); + + // Iconize JInternalFrame + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + internalFrame.setIcon(true); + } catch (PropertyVetoException ex) { + mainFrame.dispose(); + throw new RuntimeException("Iconize InternalFrame Failed"); + } + } + }); + robot.waitForIdle(); + + // DeIconize JInternalFrame + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + internalFrame.setIcon(false); + } catch (PropertyVetoException ex) { + mainFrame.dispose(); + throw new RuntimeException("DeIcoize InternalFrame " + + " Failed"); + } + } + }); + robot.waitForIdle(); + + // Restore/Undo Maximize JInternalFrame + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + internalFrame.setMaximum(false); + } catch (PropertyVetoException ex) { + mainFrame.dispose(); + throw new RuntimeException("Restore InternalFrame " + + " Failed"); + } + } + }); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + if (!internalFrame.getBounds().equals(bounds)) { + mainFrame.dispose(); + throw new RuntimeException("Regression Test Failed"); + } + } + }); + robot.waitForIdle(); + + mainFrame.dispose(); + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + UIManager.LookAndFeelInfo[] lookAndFeelArray + = UIManager.getInstalledLookAndFeels(); + for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) { + String lookAndFeelString = lookAndFeelItem.getClassName(); + if (tryLookAndFeel(lookAndFeelString)) { + // create UI + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + createUI(lookAndFeelString); + } + }); + + robot.waitForIdle(); + executeTest(robot); + } else { + throw new RuntimeException("Setting Look and Feel Failed"); + } + } + + } +} From 190c092900e680cb72c423fadbdb811ba4ec9983 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Mon, 29 Feb 2016 13:06:03 +0100 Subject: [PATCH 089/183] 8150068: Log the main G1 phases at info level Reviewed-by: sjohanss, tschatzl --- .../src/share/vm/gc/g1/g1CollectorPolicy.cpp | 9 +- hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp | 421 ++++++------------ hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp | 23 +- hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp | 5 +- hotspot/src/share/vm/gc/g1/g1RemSet.cpp | 2 +- .../src/share/vm/gc/g1/workerDataArray.cpp | 50 ++- .../src/share/vm/gc/g1/workerDataArray.hpp | 46 +- .../share/vm/gc/g1/workerDataArray.inline.hpp | 64 ++- hotspot/src/share/vm/logging/logPrefix.hpp | 1 + hotspot/test/gc/g1/TestGCLogMessages.java | 68 +-- 10 files changed, 295 insertions(+), 394 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index bd98877eded..eda5e18e1a8 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -1117,14 +1117,15 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t _short_lived_surv_rate_group->start_adding_regions(); // Do that for any other surv rate groups + double scan_hcc_time_ms = ConcurrentG1Refine::hot_card_cache_enabled() ? average_time_ms(G1GCPhaseTimes::ScanHCC) : 0.0; + if (update_stats) { double cost_per_card_ms = 0.0; - double cost_scan_hcc = average_time_ms(G1GCPhaseTimes::ScanHCC); if (_pending_cards > 0) { - cost_per_card_ms = (average_time_ms(G1GCPhaseTimes::UpdateRS) - cost_scan_hcc) / (double) _pending_cards; + cost_per_card_ms = (average_time_ms(G1GCPhaseTimes::UpdateRS) - scan_hcc_time_ms) / (double) _pending_cards; _cost_per_card_ms_seq->add(cost_per_card_ms); } - _cost_scan_hcc_seq->add(cost_scan_hcc); + _cost_scan_hcc_seq->add(scan_hcc_time_ms); double cost_per_entry_ms = 0.0; if (cards_scanned > 10) { @@ -1214,8 +1215,6 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t // Note that _mmu_tracker->max_gc_time() returns the time in seconds. double update_rs_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSetUpdatingPauseTimePercent / 100.0; - double scan_hcc_time_ms = average_time_ms(G1GCPhaseTimes::ScanHCC); - if (update_rs_time_goal_ms < scan_hcc_time_ms) { log_debug(gc, ergo, refine)("Adjust concurrent refinement thresholds (scanning the HCC expected to take longer than Update RS time goal)." "Update RS time goal: %1.2fms Scan HCC time: %1.2fms", diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp index e8c852b051f..b5dce4ffc3d 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp @@ -28,109 +28,70 @@ #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1StringDedup.hpp" #include "gc/g1/workerDataArray.inline.hpp" -#include "memory/allocation.hpp" +#include "memory/resourceArea.hpp" #include "logging/log.hpp" #include "runtime/timer.hpp" #include "runtime/os.hpp" -// Helper class for avoiding interleaved logging -class LineBuffer: public StackObj { - -private: - static const int BUFFER_LEN = 1024; - static const int INDENT_CHARS = 3; - char _buffer[BUFFER_LEN]; - int _indent_level; - int _cur; - - void vappend(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0) { - int res = vsnprintf(&_buffer[_cur], BUFFER_LEN - _cur, format, ap); - if (res != -1) { - _cur += res; - } else { - DEBUG_ONLY(warning("buffer too small in LineBuffer");) - _buffer[BUFFER_LEN -1] = 0; - _cur = BUFFER_LEN; // vsnprintf above should not add to _buffer if we are called again - } - } - -public: - explicit LineBuffer(int indent_level): _indent_level(indent_level), _cur(0) { - for (; (_cur < BUFFER_LEN && _cur < (_indent_level * INDENT_CHARS)); _cur++) { - _buffer[_cur] = ' '; - } - } - -#ifndef PRODUCT - ~LineBuffer() { - assert(_cur == _indent_level * INDENT_CHARS, "pending data in buffer - append_and_print_cr() not called?"); - } -#endif - - void append(const char* format, ...) ATTRIBUTE_PRINTF(2, 3) { - va_list ap; - va_start(ap, format); - vappend(format, ap); - va_end(ap); - } - - const char* to_string() { - _cur = _indent_level * INDENT_CHARS; - return _buffer; - } -}; - -static const char* Indents[4] = {"", " ", " ", " "}; +static const char* Indents[5] = {"", " ", " ", " ", " "}; G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : _max_gc_threads(max_gc_threads) { assert(max_gc_threads > 0, "Must have some GC threads"); - _gc_par_phases[GCWorkerStart] = new WorkerDataArray(max_gc_threads, "GC Worker Start:", false, 2); - _gc_par_phases[ExtRootScan] = new WorkerDataArray(max_gc_threads, "Ext Root Scanning:", true, 2); + _gc_par_phases[GCWorkerStart] = new WorkerDataArray(max_gc_threads, "GC Worker Start (ms):"); + _gc_par_phases[ExtRootScan] = new WorkerDataArray(max_gc_threads, "Ext Root Scanning (ms):"); // Root scanning phases - _gc_par_phases[ThreadRoots] = new WorkerDataArray(max_gc_threads, "Thread Roots:", true, 3); - _gc_par_phases[StringTableRoots] = new WorkerDataArray(max_gc_threads, "StringTable Roots:", true, 3); - _gc_par_phases[UniverseRoots] = new WorkerDataArray(max_gc_threads, "Universe Roots:", true, 3); - _gc_par_phases[JNIRoots] = new WorkerDataArray(max_gc_threads, "JNI Handles Roots:", true, 3); - _gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray(max_gc_threads, "ObjectSynchronizer Roots:", true, 3); - _gc_par_phases[FlatProfilerRoots] = new WorkerDataArray(max_gc_threads, "FlatProfiler Roots:", true, 3); - _gc_par_phases[ManagementRoots] = new WorkerDataArray(max_gc_threads, "Management Roots:", true, 3); - _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray(max_gc_threads, "SystemDictionary Roots:", true, 3); - _gc_par_phases[CLDGRoots] = new WorkerDataArray(max_gc_threads, "CLDG Roots:", true, 3); - _gc_par_phases[JVMTIRoots] = new WorkerDataArray(max_gc_threads, "JVMTI Roots:", true, 3); - _gc_par_phases[CMRefRoots] = new WorkerDataArray(max_gc_threads, "CM RefProcessor Roots:", true, 3); - _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray(max_gc_threads, "Wait For Strong CLD:", true, 3); - _gc_par_phases[WeakCLDRoots] = new WorkerDataArray(max_gc_threads, "Weak CLD Roots:", true, 3); - _gc_par_phases[SATBFiltering] = new WorkerDataArray(max_gc_threads, "SATB Filtering:", true, 3); + _gc_par_phases[ThreadRoots] = new WorkerDataArray(max_gc_threads, "Thread Roots (ms):"); + _gc_par_phases[StringTableRoots] = new WorkerDataArray(max_gc_threads, "StringTable Roots (ms):"); + _gc_par_phases[UniverseRoots] = new WorkerDataArray(max_gc_threads, "Universe Roots (ms):"); + _gc_par_phases[JNIRoots] = new WorkerDataArray(max_gc_threads, "JNI Handles Roots (ms):"); + _gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray(max_gc_threads, "ObjectSynchronizer Roots (ms):"); + _gc_par_phases[FlatProfilerRoots] = new WorkerDataArray(max_gc_threads, "FlatProfiler Roots (ms):"); + _gc_par_phases[ManagementRoots] = new WorkerDataArray(max_gc_threads, "Management Roots (ms):"); + _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray(max_gc_threads, "SystemDictionary Roots (ms):"); + _gc_par_phases[CLDGRoots] = new WorkerDataArray(max_gc_threads, "CLDG Roots (ms):"); + _gc_par_phases[JVMTIRoots] = new WorkerDataArray(max_gc_threads, "JVMTI Roots (ms):"); + _gc_par_phases[CMRefRoots] = new WorkerDataArray(max_gc_threads, "CM RefProcessor Roots (ms):"); + _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray(max_gc_threads, "Wait For Strong CLD (ms):"); + _gc_par_phases[WeakCLDRoots] = new WorkerDataArray(max_gc_threads, "Weak CLD Roots (ms):"); + _gc_par_phases[SATBFiltering] = new WorkerDataArray(max_gc_threads, "SATB Filtering (ms):"); - _gc_par_phases[UpdateRS] = new WorkerDataArray(max_gc_threads, "Update RS:", true, 2); - _gc_par_phases[ScanHCC] = new WorkerDataArray(max_gc_threads, "Scan HCC:", true, 3); - _gc_par_phases[ScanHCC]->set_enabled(ConcurrentG1Refine::hot_card_cache_enabled()); - _gc_par_phases[ScanRS] = new WorkerDataArray(max_gc_threads, "Scan RS:", true, 2); - _gc_par_phases[CodeRoots] = new WorkerDataArray(max_gc_threads, "Code Root Scanning:", true, 2); - _gc_par_phases[ObjCopy] = new WorkerDataArray(max_gc_threads, "Object Copy:", true, 2); - _gc_par_phases[Termination] = new WorkerDataArray(max_gc_threads, "Termination:", true, 2); - _gc_par_phases[GCWorkerTotal] = new WorkerDataArray(max_gc_threads, "GC Worker Total:", true, 2); - _gc_par_phases[GCWorkerEnd] = new WorkerDataArray(max_gc_threads, "GC Worker End:", false, 2); - _gc_par_phases[Other] = new WorkerDataArray(max_gc_threads, "GC Worker Other:", true, 2); + _gc_par_phases[UpdateRS] = new WorkerDataArray(max_gc_threads, "Update RS (ms):"); + if (ConcurrentG1Refine::hot_card_cache_enabled()) { + _gc_par_phases[ScanHCC] = new WorkerDataArray(max_gc_threads, "Scan HCC (ms):"); + } else { + _gc_par_phases[ScanHCC] = NULL; + } + _gc_par_phases[ScanRS] = new WorkerDataArray(max_gc_threads, "Scan RS (ms):"); + _gc_par_phases[CodeRoots] = new WorkerDataArray(max_gc_threads, "Code Root Scanning (ms):"); + _gc_par_phases[ObjCopy] = new WorkerDataArray(max_gc_threads, "Object Copy (ms):"); + _gc_par_phases[Termination] = new WorkerDataArray(max_gc_threads, "Termination (ms):"); + _gc_par_phases[GCWorkerTotal] = new WorkerDataArray(max_gc_threads, "GC Worker Total (ms):"); + _gc_par_phases[GCWorkerEnd] = new WorkerDataArray(max_gc_threads, "GC Worker End (ms):"); + _gc_par_phases[Other] = new WorkerDataArray(max_gc_threads, "GC Worker Other (ms):"); - _update_rs_processed_buffers = new WorkerDataArray(max_gc_threads, "Processed Buffers:", true, 3); + _update_rs_processed_buffers = new WorkerDataArray(max_gc_threads, "Processed Buffers:"); _gc_par_phases[UpdateRS]->link_thread_work_items(_update_rs_processed_buffers); - _termination_attempts = new WorkerDataArray(max_gc_threads, "Termination Attempts:", true, 3); + _termination_attempts = new WorkerDataArray(max_gc_threads, "Termination Attempts:"); _gc_par_phases[Termination]->link_thread_work_items(_termination_attempts); - _gc_par_phases[StringDedupQueueFixup] = new WorkerDataArray(max_gc_threads, "Queue Fixup:", true, 2); - _gc_par_phases[StringDedupTableFixup] = new WorkerDataArray(max_gc_threads, "Table Fixup:", true, 2); + if (UseStringDeduplication) { + _gc_par_phases[StringDedupQueueFixup] = new WorkerDataArray(max_gc_threads, "Queue Fixup (ms):"); + _gc_par_phases[StringDedupTableFixup] = new WorkerDataArray(max_gc_threads, "Table Fixup (ms):"); + } else { + _gc_par_phases[StringDedupQueueFixup] = NULL; + _gc_par_phases[StringDedupTableFixup] = NULL; + } - _gc_par_phases[RedirtyCards] = new WorkerDataArray(max_gc_threads, "Parallel Redirty:", true, 3); - _redirtied_cards = new WorkerDataArray(max_gc_threads, "Redirtied Cards:", true, 3); + _gc_par_phases[RedirtyCards] = new WorkerDataArray(max_gc_threads, "Parallel Redirty (ms):"); + _redirtied_cards = new WorkerDataArray(max_gc_threads, "Redirtied Cards:"); _gc_par_phases[RedirtyCards]->link_thread_work_items(_redirtied_cards); - _gc_par_phases[PreserveCMReferents] = new WorkerDataArray(max_gc_threads, "Parallel Preserve CM Refs:", true, 3); + _gc_par_phases[PreserveCMReferents] = new WorkerDataArray(max_gc_threads, "Parallel Preserve CM Refs (ms):"); } void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) { @@ -142,11 +103,10 @@ void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) { _external_accounted_time_ms = 0.0; for (int i = 0; i < GCParPhasesSentinel; i++) { - _gc_par_phases[i]->reset(); + if (_gc_par_phases[i] != NULL) { + _gc_par_phases[i]->reset(); + } } - - _gc_par_phases[StringDedupQueueFixup]->set_enabled(G1StringDedup::is_enabled()); - _gc_par_phases[StringDedupTableFixup]->set_enabled(G1StringDedup::is_enabled()); } void G1GCPhaseTimes::note_gc_end() { @@ -168,43 +128,10 @@ void G1GCPhaseTimes::note_gc_end() { } for (int i = 0; i < GCParPhasesSentinel; i++) { - _gc_par_phases[i]->verify(_active_gc_threads); - } -} - -void G1GCPhaseTimes::print_stats(const char* indent, const char* str, double value) { - log_debug(gc, phases)("%s%s: %.1lf ms", indent, str, value); -} - -double G1GCPhaseTimes::accounted_time_ms() { - // First subtract any externally accounted time - double misc_time_ms = _external_accounted_time_ms; - - // Subtract the root region scanning wait time. It's initialized to - // zero at the start of the pause. - misc_time_ms += _root_region_scan_wait_time_ms; - - misc_time_ms += _cur_collection_par_time_ms; - - // Now subtract the time taken to fix up roots in generated code - misc_time_ms += _cur_collection_code_root_fixup_time_ms; - - // Strong code root purge time - misc_time_ms += _cur_strong_code_root_purge_time_ms; - - if (G1StringDedup::is_enabled()) { - // String dedup fixup time - misc_time_ms += _cur_string_dedup_fixup_time_ms; + if (_gc_par_phases[i] != NULL) { + _gc_par_phases[i]->verify(_active_gc_threads); } - - // Subtract the time taken to clean the card table from the - // current value of "other time" - misc_time_ms += _cur_clear_ct_time_ms; - - // Remove expand heap time from "other time" - misc_time_ms += _cur_expand_heap_time_ms; - - return misc_time_ms; + } } // record the time a phase took in seconds @@ -226,196 +153,144 @@ double G1GCPhaseTimes::average_time_ms(GCParPhases phase) { return _gc_par_phases[phase]->average(_active_gc_threads) * 1000.0; } -double G1GCPhaseTimes::get_time_ms(GCParPhases phase, uint worker_i) { - return _gc_par_phases[phase]->get(worker_i) * 1000.0; -} - -double G1GCPhaseTimes::sum_time_ms(GCParPhases phase) { - return _gc_par_phases[phase]->sum(_active_gc_threads) * 1000.0; -} - -double G1GCPhaseTimes::min_time_ms(GCParPhases phase) { - return _gc_par_phases[phase]->minimum(_active_gc_threads) * 1000.0; -} - -double G1GCPhaseTimes::max_time_ms(GCParPhases phase) { - return _gc_par_phases[phase]->maximum(_active_gc_threads) * 1000.0; -} - -size_t G1GCPhaseTimes::get_thread_work_item(GCParPhases phase, uint worker_i) { - assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); - return _gc_par_phases[phase]->thread_work_items()->get(worker_i); -} - size_t G1GCPhaseTimes::sum_thread_work_items(GCParPhases phase) { assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); return _gc_par_phases[phase]->thread_work_items()->sum(_active_gc_threads); } -double G1GCPhaseTimes::average_thread_work_items(GCParPhases phase) { - assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); - return _gc_par_phases[phase]->thread_work_items()->average(_active_gc_threads); +template +void G1GCPhaseTimes::details(T* phase, const char* indent) { + LogHandle(gc, phases, task) log; + if (log.is_level(LogLevel::Trace)) { + outputStream* trace_out = log.trace_stream(); + trace_out->print("%s", indent); + phase->print_details_on(trace_out, _active_gc_threads); + } } -size_t G1GCPhaseTimes::min_thread_work_items(GCParPhases phase) { - assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); - return _gc_par_phases[phase]->thread_work_items()->minimum(_active_gc_threads); +void G1GCPhaseTimes::log_phase(WorkerDataArray* phase, uint indent, outputStream* out, bool print_sum) { + out->print("%s", Indents[indent]); + phase->print_summary_on(out, _active_gc_threads, print_sum); + details(phase, Indents[indent]); + + WorkerDataArray* work_items = phase->thread_work_items(); + if (work_items != NULL) { + out->print("%s", Indents[indent + 1]); + work_items->print_summary_on(out, _active_gc_threads, true); + details(work_items, Indents[indent + 1]); + } } -size_t G1GCPhaseTimes::max_thread_work_items(GCParPhases phase) { - assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); - return _gc_par_phases[phase]->thread_work_items()->maximum(_active_gc_threads); +void G1GCPhaseTimes::debug_phase(WorkerDataArray* phase) { + LogHandle(gc, phases) log; + if (log.is_level(LogLevel::Debug)) { + ResourceMark rm; + log_phase(phase, 2, log.debug_stream(), true); + } } -class G1GCParPhasePrinter : public StackObj { - G1GCPhaseTimes* _phase_times; - public: - G1GCParPhasePrinter(G1GCPhaseTimes* phase_times) : _phase_times(phase_times) {} - - void print(G1GCPhaseTimes::GCParPhases phase_id) { - WorkerDataArray* phase = _phase_times->_gc_par_phases[phase_id]; - - if (phase->_length == 1) { - print_single_length(phase_id, phase); - } else { - print_multi_length(phase_id, phase); - } +void G1GCPhaseTimes::trace_phase(WorkerDataArray* phase, bool print_sum) { + LogHandle(gc, phases) log; + if (log.is_level(LogLevel::Trace)) { + ResourceMark rm; + log_phase(phase, 3, log.trace_stream(), print_sum); } +} +#define PHASE_DOUBLE_FORMAT "%s%s: %.1lfms" +#define PHASE_SIZE_FORMAT "%s%s: " SIZE_FORMAT - private: - void print_single_length(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* phase) { - // No need for min, max, average and sum for only one worker - log_debug(gc, phases)("%s%s: %.1lf", Indents[phase->_indent_level], phase->_title, _phase_times->get_time_ms(phase_id, 0)); +#define info_line(str, value) \ + log_info(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[1], str, value); - WorkerDataArray* work_items = phase->_thread_work_items; - if (work_items != NULL) { - log_debug(gc, phases)("%s%s: " SIZE_FORMAT, Indents[work_items->_indent_level], work_items->_title, _phase_times->sum_thread_work_items(phase_id)); - } - } +#define debug_line(str, value) \ + log_debug(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[2], str, value); - void print_time_values(const char* indent, G1GCPhaseTimes::GCParPhases phase_id) { - if (log_is_enabled(Trace, gc)) { - LineBuffer buf(0); - uint active_length = _phase_times->_active_gc_threads; - for (uint i = 0; i < active_length; ++i) { - buf.append(" %4.1lf", _phase_times->get_time_ms(phase_id, i)); - } - const char* line = buf.to_string(); - log_trace(gc, phases)("%s%-25s%s", indent, "", line); - } - } +#define trace_line(str, value) \ + log_trace(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[3], str, value); - void print_count_values(const char* indent, G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* thread_work_items) { - if (log_is_enabled(Trace, gc)) { - LineBuffer buf(0); - uint active_length = _phase_times->_active_gc_threads; - for (uint i = 0; i < active_length; ++i) { - buf.append(" " SIZE_FORMAT, _phase_times->get_thread_work_item(phase_id, i)); - } - const char* line = buf.to_string(); - log_trace(gc, phases)("%s%-25s%s", indent, "", line); - } - } +#define trace_line_sz(str, value) \ + log_trace(gc, phases)(PHASE_SIZE_FORMAT, Indents[3], str, value); - void print_thread_work_items(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* thread_work_items) { - const char* indent = Indents[thread_work_items->_indent_level]; +#define trace_line_ms(str, value) \ + log_trace(gc, phases)(PHASE_SIZE_FORMAT, Indents[3], str, value); - assert(thread_work_items->_print_sum, "%s does not have print sum true even though it is a count", thread_work_items->_title); - - log_debug(gc, phases)("%s%-25s Min: " SIZE_FORMAT ", Avg: %4.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT ", Sum: " SIZE_FORMAT, - indent, thread_work_items->_title, - _phase_times->min_thread_work_items(phase_id), _phase_times->average_thread_work_items(phase_id), _phase_times->max_thread_work_items(phase_id), - _phase_times->max_thread_work_items(phase_id) - _phase_times->min_thread_work_items(phase_id), _phase_times->sum_thread_work_items(phase_id)); - - print_count_values(indent, phase_id, thread_work_items); - } - - void print_multi_length(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* phase) { - const char* indent = Indents[phase->_indent_level]; - - if (phase->_print_sum) { - log_debug(gc, phases)("%s%-25s Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf, Sum: %4.1lf", - indent, phase->_title, - _phase_times->min_time_ms(phase_id), _phase_times->average_time_ms(phase_id), _phase_times->max_time_ms(phase_id), - _phase_times->max_time_ms(phase_id) - _phase_times->min_time_ms(phase_id), _phase_times->sum_time_ms(phase_id)); - } else { - log_debug(gc, phases)("%s%-25s Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf", - indent, phase->_title, - _phase_times->min_time_ms(phase_id), _phase_times->average_time_ms(phase_id), _phase_times->max_time_ms(phase_id), - _phase_times->max_time_ms(phase_id) - _phase_times->min_time_ms(phase_id)); - } - - print_time_values(indent, phase_id); - - if (phase->_thread_work_items != NULL) { - print_thread_work_items(phase_id, phase->_thread_work_items); - } - } -}; +#define info_line_and_account(str, value) \ + info_line(str, value); \ + accounted_time_ms += value; void G1GCPhaseTimes::print() { note_gc_end(); - G1GCParPhasePrinter par_phase_printer(this); - + double accounted_time_ms = _external_accounted_time_ms; if (_root_region_scan_wait_time_ms > 0.0) { - print_stats(Indents[1], "Root Region Scan Waiting", _root_region_scan_wait_time_ms); + info_line_and_account("Root Region Scan Waiting", _root_region_scan_wait_time_ms); } - print_stats(Indents[1], "Parallel Time", _cur_collection_par_time_ms); - for (int i = 0; i <= GCMainParPhasesLast; i++) { - par_phase_printer.print((GCParPhases) i); + info_line_and_account("Evacuate Collection Set", _cur_collection_par_time_ms); + trace_phase(_gc_par_phases[GCWorkerStart], false); + debug_phase(_gc_par_phases[ExtRootScan]); + for (int i = ThreadRoots; i <= SATBFiltering; i++) { + trace_phase(_gc_par_phases[i]); } + debug_phase(_gc_par_phases[UpdateRS]); + if (ConcurrentG1Refine::hot_card_cache_enabled()) { + trace_phase(_gc_par_phases[ScanHCC]); + } + debug_phase(_gc_par_phases[ScanRS]); + debug_phase(_gc_par_phases[CodeRoots]); + debug_phase(_gc_par_phases[ObjCopy]); + debug_phase(_gc_par_phases[Termination]); + debug_phase(_gc_par_phases[Other]); + debug_phase(_gc_par_phases[GCWorkerTotal]); + trace_phase(_gc_par_phases[GCWorkerEnd], false); + + info_line_and_account("Code Roots", _cur_collection_code_root_fixup_time_ms + _cur_strong_code_root_purge_time_ms); + debug_line("Code Roots Fixup", _cur_collection_code_root_fixup_time_ms); + debug_line("Code Roots Purge", _cur_strong_code_root_purge_time_ms); - print_stats(Indents[1], "Code Root Fixup", _cur_collection_code_root_fixup_time_ms); - print_stats(Indents[1], "Code Root Purge", _cur_strong_code_root_purge_time_ms); if (G1StringDedup::is_enabled()) { - print_stats(Indents[1], "String Dedup Fixup", _cur_string_dedup_fixup_time_ms); - for (int i = StringDedupPhasesFirst; i <= StringDedupPhasesLast; i++) { - par_phase_printer.print((GCParPhases) i); - } + info_line_and_account("String Dedup Fixup", _cur_string_dedup_fixup_time_ms); + debug_phase(_gc_par_phases[StringDedupQueueFixup]); + debug_phase(_gc_par_phases[StringDedupTableFixup]); } - print_stats(Indents[1], "Clear CT", _cur_clear_ct_time_ms); - print_stats(Indents[1], "Expand Heap After Collection", _cur_expand_heap_time_ms); - double misc_time_ms = _gc_pause_time_ms - accounted_time_ms(); - print_stats(Indents[1], "Other", misc_time_ms); + info_line_and_account("Clear Card Table", _cur_clear_ct_time_ms); + info_line_and_account("Expand Heap After Collection", _cur_expand_heap_time_ms); + + double free_cset_time = _recorded_young_free_cset_time_ms + _recorded_non_young_free_cset_time_ms; + info_line_and_account("Free Collection Set", free_cset_time); + debug_line("Young Free Collection Set", _recorded_young_free_cset_time_ms); + debug_line("Non-Young Free Collection Set", _recorded_non_young_free_cset_time_ms); + info_line_and_account("Merge Per-Thread State", _recorded_merge_pss_time_ms); + + info_line("Other", _gc_pause_time_ms - accounted_time_ms); if (_cur_verify_before_time_ms > 0.0) { - print_stats(Indents[2], "Verify Before", _cur_verify_before_time_ms); + debug_line("Verify Before", _cur_verify_before_time_ms); } if (G1CollectedHeap::heap()->evacuation_failed()) { double evac_fail_handling = _cur_evac_fail_recalc_used + _cur_evac_fail_remove_self_forwards + _cur_evac_fail_restore_remsets; - print_stats(Indents[2], "Evacuation Failure", evac_fail_handling); - log_trace(gc, phases)("%sRecalculate Used: %.1lf ms", Indents[3], _cur_evac_fail_recalc_used); - log_trace(gc, phases)("%sRemove Self Forwards: %.1lf ms", Indents[3], _cur_evac_fail_remove_self_forwards); - log_trace(gc, phases)("%sRestore RemSet: %.1lf ms", Indents[3], _cur_evac_fail_restore_remsets); + debug_line("Evacuation Failure", evac_fail_handling); + trace_line("Recalculate Used", _cur_evac_fail_recalc_used); + trace_line("Remove Self Forwards",_cur_evac_fail_remove_self_forwards); + trace_line("Restore RemSet", _cur_evac_fail_restore_remsets); } - print_stats(Indents[2], "Choose CSet", - (_recorded_young_cset_choice_time_ms + - _recorded_non_young_cset_choice_time_ms)); - print_stats(Indents[2], "Preserve CM Refs", _recorded_preserve_cm_referents_time_ms); - print_stats(Indents[2], "Ref Proc", _cur_ref_proc_time_ms); - print_stats(Indents[2], "Ref Enq", _cur_ref_enq_time_ms); - print_stats(Indents[2], "Redirty Cards", _recorded_redirty_logged_cards_time_ms); - par_phase_printer.print(RedirtyCards); - par_phase_printer.print(PreserveCMReferents); + debug_line("Choose CSet", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms)); + debug_line("Preserve CM Refs", _recorded_preserve_cm_referents_time_ms); + debug_line("Ref Proc", _cur_ref_proc_time_ms); + debug_line("Ref Enq", _cur_ref_enq_time_ms); + debug_line("Redirty Cards", _recorded_redirty_logged_cards_time_ms); + trace_phase(_gc_par_phases[RedirtyCards]); + trace_phase(_gc_par_phases[PreserveCMReferents]); if (G1EagerReclaimHumongousObjects) { - print_stats(Indents[2], "Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); - - log_trace(gc, phases)("%sHumongous Total: " SIZE_FORMAT, Indents[3], _cur_fast_reclaim_humongous_total); - log_trace(gc, phases)("%sHumongous Candidate: " SIZE_FORMAT, Indents[3], _cur_fast_reclaim_humongous_candidates); - print_stats(Indents[2], "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms); - log_trace(gc, phases)("%sHumongous Reclaimed: " SIZE_FORMAT, Indents[3], _cur_fast_reclaim_humongous_reclaimed); + debug_line("Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); + trace_line_sz("Humongous Total", _cur_fast_reclaim_humongous_total); + trace_line_sz("Humongous Candidate", _cur_fast_reclaim_humongous_candidates); + debug_line("Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms); + trace_line_sz("Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed); } - print_stats(Indents[2], "Free CSet", - (_recorded_young_free_cset_time_ms + - _recorded_non_young_free_cset_time_ms)); - log_trace(gc, phases)("%sYoung Free CSet: %.1lf ms", Indents[3], _recorded_young_free_cset_time_ms); - log_trace(gc, phases)("%sNon-Young Free CSet: %.1lf ms", Indents[3], _recorded_non_young_free_cset_time_ms); - print_stats(Indents[2], "Merge Per-Thread State", _recorded_merge_pss_time_ms); if (_cur_verify_after_time_ms > 0.0) { - print_stats(Indents[2], "Verify After", _cur_verify_after_time_ms); + debug_line("Verify After", _cur_verify_after_time_ms); } } diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp index c474659a849..e87075b5e93 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp @@ -32,8 +32,6 @@ class LineBuffer; template class WorkerDataArray; class G1GCPhaseTimes : public CHeapObj { - friend class G1GCParPhasePrinter; - uint _active_gc_threads; uint _max_gc_threads; jlong _gc_start_counter; @@ -125,11 +123,14 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_verify_before_time_ms; double _cur_verify_after_time_ms; - // Helper methods for detailed logging - void print_stats(const char*, const char* str, double value); - void note_gc_end(); + template + void details(T* phase, const char* indent); + void log_phase(WorkerDataArray* phase, uint indent, outputStream* out, bool print_sum); + void debug_phase(WorkerDataArray* phase); + void trace_phase(WorkerDataArray* phase, bool print_sum = true); + public: G1GCPhaseTimes(uint max_gc_threads); void note_gc_start(uint active_gc_threads); @@ -148,16 +149,6 @@ class G1GCPhaseTimes : public CHeapObj { size_t sum_thread_work_items(GCParPhases phase); - private: - double get_time_ms(GCParPhases phase, uint worker_i); - double sum_time_ms(GCParPhases phase); - double min_time_ms(GCParPhases phase); - double max_time_ms(GCParPhases phase); - size_t get_thread_work_item(GCParPhases phase, uint worker_i); - double average_thread_work_items(GCParPhases phase); - size_t min_thread_work_items(GCParPhases phase); - size_t max_thread_work_items(GCParPhases phase); - public: void record_clear_ct_time(double ms) { @@ -263,8 +254,6 @@ class G1GCPhaseTimes : public CHeapObj { _external_accounted_time_ms += time_ms; } - double accounted_time_ms(); - double cur_collection_start_sec() { return _cur_collection_start_sec; } diff --git a/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp b/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp index b7c176d632b..013be1a12f8 100644 --- a/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp +++ b/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp @@ -81,10 +81,7 @@ jbyte* G1HotCardCache::insert(jbyte* card_ptr) { } void G1HotCardCache::drain(CardTableEntryClosure* cl, uint worker_i) { - if (!default_use_cache()) { - assert(_hot_cache == NULL, "Logic"); - return; - } + assert(default_use_cache(), "Drain only necessary if we use the hot card cache."); assert(_hot_cache != NULL, "Logic"); assert(!use_cache(), "cache should be disabled"); diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp index 3d2917a2184..8c31430e185 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp @@ -238,7 +238,7 @@ void G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, uint worker_i) { RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, into_cset_dcq); G1GCParPhaseTimesTracker x(_g1p->phase_times(), G1GCPhaseTimes::UpdateRS, worker_i); - { + if (ConcurrentG1Refine::hot_card_cache_enabled()) { // Apply the closure to the entries of the hot card cache. G1GCParPhaseTimesTracker y(_g1p->phase_times(), G1GCPhaseTimes::ScanHCC, worker_i); _g1->iterate_hcc_closure(&into_cset_update_rs_cl, worker_i); diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.cpp b/hotspot/src/share/vm/gc/g1/workerDataArray.cpp index 0e3305d5c2a..62b66559a53 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.cpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.cpp @@ -24,18 +24,53 @@ #include "precompiled.hpp" #include "gc/g1/workerDataArray.inline.hpp" +#include "utilities/ostream.hpp" + +template <> +void WorkerDataArray::WDAPrinter::summary(outputStream* out, const char* title, double min, double avg, double max, double diff, double sum, bool print_sum) { + out->print("%-25s Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf", title, min * MILLIUNITS, avg * MILLIUNITS, max * MILLIUNITS, diff* MILLIUNITS); + if (print_sum) { + out->print_cr(", Sum: %4.1lf", sum * MILLIUNITS); + } else { + out->cr(); + } +} + +template <> +void WorkerDataArray::WDAPrinter::summary(outputStream* out, const char* title, size_t min, double avg, size_t max, size_t diff, size_t sum, bool print_sum) { + out->print("%-25s Min: " SIZE_FORMAT ", Avg: %4.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT, title, min, avg, max, diff); + if (print_sum) { + out->print_cr(", Sum: " SIZE_FORMAT, sum); + } else { + out->cr(); + } +} + +template <> +void WorkerDataArray::WDAPrinter::details(const WorkerDataArray* phase, outputStream* out, uint active_threads) { + out->print("%-25s", ""); + for (uint i = 0; i < active_threads; ++i) { + out->print(" %4.1lf", phase->get(i) * 1000.0); + } + out->cr(); +} + +template <> +void WorkerDataArray::WDAPrinter::details(const WorkerDataArray* phase, outputStream* out, uint active_threads) { + out->print("%-25s", ""); + for (uint i = 0; i < active_threads; ++i) { + out->print(" " SIZE_FORMAT, phase->get(i)); + } + out->cr(); +} #ifndef PRODUCT void WorkerDataArray_test() { const uint length = 3; const char* title = "Test array"; - const bool print_sum = false; - const uint indent_level = 2; - WorkerDataArray array(length, title, print_sum, indent_level); + WorkerDataArray array(length, title); assert(strncmp(array.title(), title, strlen(title)) == 0 , "Expected titles to match"); - assert(array.should_print_sum() == print_sum, "Expected should_print_sum to match print_sum"); - assert(array.indentation() == indent_level, "Expected indentation to match"); const size_t expected[length] = {5, 3, 7}; for (uint i = 0; i < length; i++) { @@ -46,10 +81,7 @@ void WorkerDataArray_test() { } assert(array.sum(length) == (5 + 3 + 7), "Expected sums to match"); - assert(array.minimum(length) == 3, "Expected mininum to match"); - assert(array.maximum(length) == 7, "Expected maximum to match"); - assert(array.diff(length) == (7 - 3), "Expected diffs to match"); - assert(array.average(length) == 5, "Expected averages to match"); + assert(array.average(length) == 5.0, "Expected averages to match"); for (uint i = 0; i < length; i++) { array.add(i, 1); diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.hpp b/hotspot/src/share/vm/gc/g1/workerDataArray.hpp index 09f0b61a5f7..e1e972327ea 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.hpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.hpp @@ -22,18 +22,19 @@ * */ +#ifndef SHARE_VM_GC_G1_WORKERDATAARRAY_HPP +#define SHARE_VM_GC_G1_WORKERDATAARRAY_HPP + #include "memory/allocation.hpp" #include "utilities/debug.hpp" +class outputStream; + template class WorkerDataArray : public CHeapObj { - friend class G1GCParPhasePrinter; T* _data; uint _length; const char* _title; - bool _print_sum; - uint _indent_level; - bool _enabled; WorkerDataArray* _thread_work_items; @@ -42,11 +43,7 @@ class WorkerDataArray : public CHeapObj { void set_all(T value); public: - WorkerDataArray(uint length, - const char* title, - bool print_sum, - uint indent_level); - + WorkerDataArray(uint length, const char* title); ~WorkerDataArray(); void link_thread_work_items(WorkerDataArray* thread_work_items); @@ -62,27 +59,30 @@ class WorkerDataArray : public CHeapObj { double average(uint active_threads) const; T sum(uint active_threads) const; - T minimum(uint active_threads) const; - T maximum(uint active_threads) const; - T diff(uint active_threads) const; - - uint indentation() const { - return _indent_level; - } const char* title() const { return _title; } - bool should_print_sum() const { - return _print_sum; - } - void clear(); - void set_enabled(bool enabled) { - _enabled = enabled; - } void reset() PRODUCT_RETURN; void verify(uint active_threads) const PRODUCT_RETURN; + + + private: + class WDAPrinter { + public: + static void summary(outputStream* out, const char* title, double min, double avg, double max, double diff, double sum, bool print_sum); + static void summary(outputStream* out, const char* title, size_t min, double avg, size_t max, size_t diff, size_t sum, bool print_sum); + + static void details(const WorkerDataArray* phase, outputStream* out, uint active_threads); + static void details(const WorkerDataArray* phase, outputStream* out, uint active_threads); + }; + + public: + void print_summary_on(outputStream* out, uint active_threads, bool print_sum = true) const; + void print_details_on(outputStream* out, uint active_threads) const; }; + +#endif // SHARE_VM_GC_G1_WORKERDATAARRAY_HPP diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp b/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp index 713eb125cff..7b4df8628b8 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp @@ -22,20 +22,18 @@ * */ +#ifndef SHARE_VM_GC_G1_WORKERDATAARRAY_INLINE_HPP +#define SHARE_VM_GC_G1_WORKERDATAARRAY_INLINE_HPP + #include "gc/g1/workerDataArray.hpp" #include "memory/allocation.inline.hpp" +#include "utilities/ostream.hpp" template -WorkerDataArray::WorkerDataArray(uint length, - const char* title, - bool print_sum, - uint indent_level) : +WorkerDataArray::WorkerDataArray(uint length, const char* title) : _title(title), _length(0), - _print_sum(print_sum), - _indent_level(indent_level), - _thread_work_items(NULL), - _enabled(true) { + _thread_work_items(NULL) { assert(length > 0, "Must have some workers to store data for"); _length = length; _data = NEW_C_HEAP_ARRAY(T, _length, mtGC); @@ -93,29 +91,6 @@ T WorkerDataArray::sum(uint active_threads) const { return s; } -template -T WorkerDataArray::minimum(uint active_threads) const { - T min = get(0); - for (uint i = 1; i < active_threads; ++i) { - min = MIN2(min, get(i)); - } - return min; -} - -template -T WorkerDataArray::maximum(uint active_threads) const { - T max = get(0); - for (uint i = 1; i < active_threads; ++i) { - max = MAX2(max, get(i)); - } - return max; -} - -template -T WorkerDataArray::diff(uint active_threads) const { - return maximum(active_threads) - minimum(active_threads); -} - template void WorkerDataArray::clear() { set_all(0); @@ -128,6 +103,27 @@ void WorkerDataArray::set_all(T value) { } } +template +void WorkerDataArray::print_summary_on(outputStream* out, uint active_threads, bool print_sum) const { + T max = get(0); + T min = max; + T sum = 0; + for (uint i = 1; i < active_threads; ++i) { + T value = get(i); + max = MAX2(max, value); + min = MIN2(min, value); + sum += value; + } + T diff = max - min; + double avg = sum / (double) active_threads; + WDAPrinter::summary(out, title(), min, avg, max, diff, sum, print_sum); +} + +template +void WorkerDataArray::print_details_on(outputStream* out, uint active_threads) const { + WDAPrinter::details(this, out, active_threads); +} + #ifndef PRODUCT template void WorkerDataArray::reset() { @@ -139,10 +135,6 @@ void WorkerDataArray::reset() { template void WorkerDataArray::verify(uint active_threads) const { - if (!_enabled) { - return; - } - assert(active_threads <= _length, "Wrong number of active threads"); for (uint i = 0; i < active_threads; i++) { assert(_data[i] != uninitialized(), @@ -163,3 +155,5 @@ inline double WorkerDataArray::uninitialized() const { return -1.0; } #endif + +#endif // SHARE_VM_GC_G1_WORKERDATAARRAY_INLINE_HPP diff --git a/hotspot/src/share/vm/logging/logPrefix.hpp b/hotspot/src/share/vm/logging/logPrefix.hpp index 039e5f44416..213fa7c2806 100644 --- a/hotspot/src/share/vm/logging/logPrefix.hpp +++ b/hotspot/src/share/vm/logging/logPrefix.hpp @@ -58,6 +58,7 @@ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, metaspace)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, start)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, task)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, plab)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, region)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, remset)) \ diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index 0659c98f1c9..81526644c59 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -38,10 +38,24 @@ import jdk.test.lib.OutputAnalyzer; public class TestGCLogMessages { private enum Level { - OFF, DEBUG, TRACE; - public boolean lessOrEqualTo(Level other) { + OFF(""), + INFO("info"), + DEBUG("debug"), + TRACE("trace"); + + private String logName; + + Level(String logName) { + this.logName = logName; + } + + public boolean lessThan(Level other) { return this.compareTo(other) < 0; } + + public String toString() { + return logName; + } } private class LogMessageWithLevel { @@ -56,48 +70,48 @@ public class TestGCLogMessages { private LogMessageWithLevel allLogMessages[] = new LogMessageWithLevel[] { // Update RS - new LogMessageWithLevel("Scan HCC", Level.DEBUG), + new LogMessageWithLevel("Scan HCC", Level.TRACE), // Ext Root Scan - new LogMessageWithLevel("Thread Roots:", Level.DEBUG), - new LogMessageWithLevel("StringTable Roots:", Level.DEBUG), - new LogMessageWithLevel("Universe Roots:", Level.DEBUG), - new LogMessageWithLevel("JNI Handles Roots:", Level.DEBUG), - new LogMessageWithLevel("ObjectSynchronizer Roots:", Level.DEBUG), - new LogMessageWithLevel("FlatProfiler Roots", Level.DEBUG), - new LogMessageWithLevel("Management Roots", Level.DEBUG), - new LogMessageWithLevel("SystemDictionary Roots", Level.DEBUG), - new LogMessageWithLevel("CLDG Roots", Level.DEBUG), - new LogMessageWithLevel("JVMTI Roots", Level.DEBUG), - new LogMessageWithLevel("SATB Filtering", Level.DEBUG), - new LogMessageWithLevel("CM RefProcessor Roots", Level.DEBUG), - new LogMessageWithLevel("Wait For Strong CLD", Level.DEBUG), - new LogMessageWithLevel("Weak CLD Roots", Level.DEBUG), + new LogMessageWithLevel("Thread Roots", Level.TRACE), + new LogMessageWithLevel("StringTable Roots", Level.TRACE), + new LogMessageWithLevel("Universe Roots", Level.TRACE), + new LogMessageWithLevel("JNI Handles Roots", Level.TRACE), + new LogMessageWithLevel("ObjectSynchronizer Roots", Level.TRACE), + new LogMessageWithLevel("FlatProfiler Roots", Level.TRACE), + new LogMessageWithLevel("Management Roots", Level.TRACE), + new LogMessageWithLevel("SystemDictionary Roots", Level.TRACE), + new LogMessageWithLevel("CLDG Roots", Level.TRACE), + new LogMessageWithLevel("JVMTI Roots", Level.TRACE), + new LogMessageWithLevel("SATB Filtering", Level.TRACE), + new LogMessageWithLevel("CM RefProcessor Roots", Level.TRACE), + new LogMessageWithLevel("Wait For Strong CLD", Level.TRACE), + new LogMessageWithLevel("Weak CLD Roots", Level.TRACE), // Redirty Cards new LogMessageWithLevel("Redirty Cards", Level.DEBUG), - new LogMessageWithLevel("Parallel Redirty", Level.DEBUG), - new LogMessageWithLevel("Redirtied Cards", Level.DEBUG), + new LogMessageWithLevel("Parallel Redirty", Level.TRACE), + new LogMessageWithLevel("Redirtied Cards", Level.TRACE), // Misc Top-level - new LogMessageWithLevel("Code Root Purge", Level.DEBUG), - new LogMessageWithLevel("String Dedup Fixup", Level.DEBUG), - new LogMessageWithLevel("Expand Heap After Collection", Level.DEBUG), + new LogMessageWithLevel("Code Roots Purge", Level.DEBUG), + new LogMessageWithLevel("String Dedup Fixup", Level.INFO), + new LogMessageWithLevel("Expand Heap After Collection", Level.INFO), // Free CSet - new LogMessageWithLevel("Young Free CSet", Level.TRACE), - new LogMessageWithLevel("Non-Young Free CSet", Level.TRACE), + new LogMessageWithLevel("Young Free Collection Set", Level.DEBUG), + new LogMessageWithLevel("Non-Young Free Collection Set", Level.DEBUG), // Humongous Eager Reclaim new LogMessageWithLevel("Humongous Reclaim", Level.DEBUG), new LogMessageWithLevel("Humongous Register", Level.DEBUG), // Preserve CM Referents new LogMessageWithLevel("Preserve CM Refs", Level.DEBUG), // Merge PSS - new LogMessageWithLevel("Merge Per-Thread State", Level.DEBUG), + new LogMessageWithLevel("Merge Per-Thread State", Level.INFO), }; void checkMessagesAtLevel(OutputAnalyzer output, LogMessageWithLevel messages[], Level level) throws Exception { for (LogMessageWithLevel l : messages) { - if (level.lessOrEqualTo(l.level)) { + if (level.lessThan(l.level)) { output.shouldNotContain(l.message); } else { - output.shouldContain(l.message); + output.shouldMatch("\\[" + l.level + ".*" + l.message); } } } From cd790e86a4d52a177cc7f3e99d5f9abe31107b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Tue, 1 Mar 2016 23:41:57 +0100 Subject: [PATCH 090/183] 8143228: Update module exports for Java Flight Recorder Reviewed-by: alanb, egahlin --- common/bin/compare_exceptions.sh.incl | 2 -- modules.xml | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/common/bin/compare_exceptions.sh.incl b/common/bin/compare_exceptions.sh.incl index fb68ede81d4..30ae49c6fc1 100644 --- a/common/bin/compare_exceptions.sh.incl +++ b/common/bin/compare_exceptions.sh.incl @@ -185,7 +185,6 @@ if [ "$OPENJDK_TARGET_OS" = "solaris" ] && [ "$OPENJDK_TARGET_CPU" = "x86_64" ]; ./lib/amd64/libjava.so ./lib/amd64/libjawt.so ./lib/amd64/libjdwp.so - ./lib/amd64/libjfr.so ./lib/amd64/libjpeg.so ./lib/amd64/libjsdt.so ./lib/amd64/libjsound.so @@ -321,7 +320,6 @@ if [ "$OPENJDK_TARGET_OS" = "solaris" ] && [ "$OPENJDK_TARGET_CPU" = "sparcv9" ] ./lib/sparcv9/libjava.so ./lib/sparcv9/libjawt.so ./lib/sparcv9/libjdwp.so - ./lib/sparcv9/libjfr.so ./lib/sparcv9/libjpeg.so ./lib/sparcv9/libjsdt.so ./lib/sparcv9/libjsound.so diff --git a/modules.xml b/modules.xml index 75a523a8cc8..7c3ab34f827 100644 --- a/modules.xml +++ b/modules.xml @@ -239,6 +239,7 @@ java.xml jdk.charsets jdk.management.resource + jdk.jfr jdk.net jdk.scripting.nashorn jdk.vm.ci @@ -249,6 +250,22 @@ java.management jdk.jvmstat + + jdk.internal.org.xml.sax + jdk.jfr + + + jdk.internal.org.xml.sax.helpers + jdk.jfr + + + jdk.internal.util.xml + jdk.jfr + + + jdk.internal.util.xml.impl + jdk.jfr + jdk.internal.org.objectweb.asm java.instrument @@ -314,6 +331,7 @@ jdk.vm.ci jdk.zipfs java.instrument + jdk.jfr sun.net @@ -914,6 +932,7 @@ sun.management.spi jdk.management jdk.management.cmm + jdk.management.jfr From 2d3d1ed1476a9af6f22d25754dbe04d6cd260dfe Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Mon, 29 Feb 2016 22:55:13 +0900 Subject: [PATCH 091/183] 8150723: HSDB toolbar icons are missing Reviewed-by: erikj, dsamersoff --- make/CompileJavaModules.gmk | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index 8593b3c784f..e8928e2130d 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -368,21 +368,7 @@ jdk.compiler_CLEAN_FILES := $(wildcard \ ################################################################################ jdk.hotspot.agent_ADD_JAVAC_FLAGS := $(DISABLE_WARNINGS),-overrides -jdk.hotspot.agent_COPY := .png sa.js .properties - -ifeq ($(MODULE), jdk.hotspot.agent) - ### Copy gif files - # Special handling to copy gif files in images/toolbarButtonGraphics \ - # -> classes/toolbarButtonGraphics. - # These can't be handled by COPY to SetupJavaCompilation since they chop off - # one directory level. - $(eval $(call SetupCopyFiles, COPY_SA_IMAGES, \ - SRC := $(HOTSPOT_TOPDIR)/src/jdk.hotspot.agent/share/classes/images, \ - DEST := $(JDK_OUTPUTDIR)/modules/$(MODULE), \ - FILES := $(wildcard $(HOTSPOT_TOPDIR)/src/jdk.hotspot.agent/share/classes/images/*/*/*.gif), \ - )) - jdk.hotspot.agent: $(COPY_SA_IMAGES) -endif +jdk.hotspot.agent_COPY := .gif .png sa.js .properties ################################################################################ From dbaa70361f45f8801b4854cce64cd64a1da29329 Mon Sep 17 00:00:00 2001 From: Derek White Date: Mon, 29 Feb 2016 11:32:12 -0500 Subject: [PATCH 092/183] 8140600: Convert unnecessarily malloc'd Monitors to value members Change a malloc'd monitor into an embedded monitor. Reviewed-by: tschatzl, kbarrett --- .../vm/gc/g1/g1YoungRemSetSamplingThread.cpp | 20 +++++++++---------- .../vm/gc/g1/g1YoungRemSetSamplingThread.hpp | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp index 8c8d216478c..060b7feb3ad 100644 --- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp +++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp @@ -57,21 +57,21 @@ void G1YoungRemSetSamplingThread::stop() { } } -G1YoungRemSetSamplingThread::G1YoungRemSetSamplingThread() : ConcurrentGCThread() { - _monitor = new Monitor(Mutex::nonleaf, - "G1YoungRemSetSamplingThread monitor", - true, - Monitor::_safepoint_check_never); - +G1YoungRemSetSamplingThread::G1YoungRemSetSamplingThread() : + ConcurrentGCThread(), + _monitor(Mutex::nonleaf, + "G1YoungRemSetSamplingThread monitor", + true, + Monitor::_safepoint_check_never) { set_name("G1 Young RemSet Sampling"); create_and_start(); } void G1YoungRemSetSamplingThread::sleep_before_next_cycle() { - MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); + MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag); if (!_should_terminate) { intx waitms = G1ConcRefinementServiceIntervalMillis; // 300, really should be? - _monitor->wait(Mutex::_no_safepoint_check_flag, waitms); + _monitor.wait(Mutex::_no_safepoint_check_flag, waitms); } } @@ -92,8 +92,8 @@ void G1YoungRemSetSamplingThread::run_service() { } void G1YoungRemSetSamplingThread::stop_service() { - MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); - _monitor->notify(); + MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag); + _monitor.notify(); } void G1YoungRemSetSamplingThread::sample_young_list_rs_lengths() { diff --git a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp index d5837e42aee..78e82e7e352 100644 --- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp +++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, 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 @@ -41,7 +41,7 @@ // increase the young gen size to keep pause time length goal. class G1YoungRemSetSamplingThread: public ConcurrentGCThread { private: - Monitor* _monitor; + Monitor _monitor; void sample_young_list_rs_lengths(); From 5a873632f38264c0f5cd14898fedaa3177f12274 Mon Sep 17 00:00:00 2001 From: Max Ockner Date: Mon, 29 Feb 2016 16:58:09 -0500 Subject: [PATCH 093/183] 8149064: TraceProtectionDomainVerification has been converted to Unified Logging TraceProtectionDomainVerification has been converted to Unified Logging with tag protectiondomain. Reviewed-by: coleenp, iklam --- hotspot/src/share/vm/classfile/dictionary.cpp | 6 +- hotspot/src/share/vm/classfile/dictionary.hpp | 5 +- .../share/vm/classfile/systemDictionary.cpp | 24 +++---- hotspot/src/share/vm/logging/logTag.hpp | 1 + hotspot/src/share/vm/runtime/globals.hpp | 3 - .../ProtectionDomainVerificationTest.java | 62 +++++++++++++++++++ 6 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 hotspot/test/runtime/logging/ProtectionDomainVerificationTest.java diff --git a/hotspot/src/share/vm/classfile/dictionary.cpp b/hotspot/src/share/vm/classfile/dictionary.cpp index 6f70ef9b47e..61c3bad0f8e 100644 --- a/hotspot/src/share/vm/classfile/dictionary.cpp +++ b/hotspot/src/share/vm/classfile/dictionary.cpp @@ -135,8 +135,10 @@ void DictionaryEntry::add_protection_domain(Dictionary* dict, oop protection_dom // via a store to _pd_set. OrderAccess::release_store_ptr(&_pd_set, new_head); } - if (TraceProtectionDomainVerification && WizardMode) { - print(); + if (log_is_enabled(Trace, protectiondomain)) { + ResourceMark rm; + outputStream* log = LogHandle(protectiondomain)::trace_stream(); + print_count(log); } } diff --git a/hotspot/src/share/vm/classfile/dictionary.hpp b/hotspot/src/share/vm/classfile/dictionary.hpp index a77f33717f3..a873fdd3e47 100644 --- a/hotspot/src/share/vm/classfile/dictionary.hpp +++ b/hotspot/src/share/vm/classfile/dictionary.hpp @@ -29,6 +29,7 @@ #include "oops/instanceKlass.hpp" #include "oops/oop.hpp" #include "utilities/hashtable.hpp" +#include "utilities/ostream.hpp" class DictionaryEntry; class PSPromotionManager; @@ -323,14 +324,14 @@ class DictionaryEntry : public HashtableEntry { return (klass->name() == class_name && _loader_data == loader_data); } - void print() { + void print_count(outputStream *st) { int count = 0; for (ProtectionDomainEntry* current = _pd_set; current != NULL; current = current->_next) { count++; } - tty->print_cr("pd set = #%d", count); + st->print_cr("pd set count = #%d", count); } }; diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 2a61613e910..549182e82cf 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -430,12 +430,15 @@ void SystemDictionary::validate_protection_domain(instanceKlassHandle klass, // Now we have to call back to java to check if the initating class has access JavaValue result(T_VOID); - if (TraceProtectionDomainVerification) { + if (log_is_enabled(Debug, protectiondomain)) { + ResourceMark rm; // Print out trace information - tty->print_cr("Checking package access"); - tty->print(" - class loader: "); class_loader()->print_value_on(tty); tty->cr(); - tty->print(" - protection domain: "); protection_domain()->print_value_on(tty); tty->cr(); - tty->print(" - loading: "); klass()->print_value_on(tty); tty->cr(); + outputStream* log = LogHandle(protectiondomain)::debug_stream(); + log->print_cr("Checking package access"); + log->print("class loader: "); class_loader()->print_value_on(log); + log->print(" protection domain: "); protection_domain()->print_value_on(log); + log->print(" loading: "); klass()->print_value_on(log); + log->cr(); } KlassHandle system_loader(THREAD, SystemDictionary::ClassLoader_klass()); @@ -448,13 +451,10 @@ void SystemDictionary::validate_protection_domain(instanceKlassHandle klass, protection_domain, THREAD); - if (TraceProtectionDomainVerification) { - if (HAS_PENDING_EXCEPTION) { - tty->print_cr(" -> DENIED !!!!!!!!!!!!!!!!!!!!!"); - } else { - tty->print_cr(" -> granted"); - } - tty->cr(); + if (HAS_PENDING_EXCEPTION) { + log_debug(protectiondomain)("DENIED !!!!!!!!!!!!!!!!!!!!!"); + } else { + log_debug(protectiondomain)("granted"); } if (HAS_PENDING_EXCEPTION) return; diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp index 08a78c6b2ba..d292c8339e9 100644 --- a/hotspot/src/share/vm/logging/logTag.hpp +++ b/hotspot/src/share/vm/logging/logTag.hpp @@ -67,6 +67,7 @@ LOG_TAG(phases) \ LOG_TAG(plab) \ LOG_TAG(promotion) \ + LOG_TAG(protectiondomain) /* "Trace protection domain verification" */ \ LOG_TAG(ref) \ LOG_TAG(refine) \ LOG_TAG(region) \ diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 848bb5d2607..672b3c340ab 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1478,9 +1478,6 @@ public: develop(bool, TraceCompiledIC, false, \ "Trace changes of compiled IC") \ \ - develop(bool, TraceProtectionDomainVerification, false, \ - "Trace protection domain verification") \ - \ develop(bool, TraceClearedExceptions, false, \ "Print when an exception is forcibly cleared") \ \ diff --git a/hotspot/test/runtime/logging/ProtectionDomainVerificationTest.java b/hotspot/test/runtime/logging/ProtectionDomainVerificationTest.java new file mode 100644 index 00000000000..57790ad1248 --- /dev/null +++ b/hotspot/test/runtime/logging/ProtectionDomainVerificationTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test ProtectionDomainVerificationTest + * @bug 8149064 + * @library /testlibrary + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.Platform jdk.test.lib.ProcessTools + * @run driver ProtectionDomainVerificationTest + */ + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.Platform; +import jdk.test.lib.ProcessTools; + +public class ProtectionDomainVerificationTest { + + public static void main(String... args) throws Exception { + + // -Xlog:protectiondomain=trace + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:protectiondomain=trace", + "-Xmx64m", + Hello.class.getName()); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldContain("[protectiondomain] Checking package access"); + out.shouldContain("[protectiondomain] pd set count = #"); + + // -Xlog:protectiondomain=debug + pb = ProcessTools.createJavaProcessBuilder("-Xlog:protectiondomain=debug", + "-Xmx64m", + Hello.class.getName()); + out = new OutputAnalyzer(pb.start()); + out.shouldContain("[protectiondomain] Checking package access"); + out.shouldNotContain("pd set count = #"); + } + + public static class Hello { + public static void main(String[] args) { + System.out.print("Hello!"); + } + } +} From 12d9b13eee9abdb71a4e4817e25a2b3dd17b9f88 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Tue, 1 Mar 2016 09:42:19 +0100 Subject: [PATCH 094/183] 8150822: Fix typo in JDK-8150201 Reviewed-by: ihse, dholmes --- hotspot/make/solaris/makefiles/amd64.make | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/make/solaris/makefiles/amd64.make b/hotspot/make/solaris/makefiles/amd64.make index 7b1bdf3d8b3..3eb6dee9b92 100644 --- a/hotspot/make/solaris/makefiles/amd64.make +++ b/hotspot/make/solaris/makefiles/amd64.make @@ -39,7 +39,7 @@ OPT_CFLAGS/c1_LinearScan.o = -xO2 # of OPT_CFLAGS. Restore it here. ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) OPT_CFLAGS/generateOptoStub.o += -g0 -xs - OPT_CFLAGS/LinearScan.o += -g0 -xs + OPT_CFLAGS/c1_LinearScan.o += -g0 -xs endif else From a1b61d28278f48e2ad0b8072e4ce04ea41df5a25 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Tue, 1 Mar 2016 20:06:47 +0300 Subject: [PATCH 095/183] 8150933: System::arraycopy intrinsic doesn't mark mismatched loads Reviewed-by: kvn, shade --- hotspot/src/share/vm/opto/macroArrayCopy.cpp | 10 ++++++++-- hotspot/src/share/vm/opto/memnode.cpp | 9 ++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/hotspot/src/share/vm/opto/macroArrayCopy.cpp b/hotspot/src/share/vm/opto/macroArrayCopy.cpp index 82816b2462b..17065895bff 100644 --- a/hotspot/src/share/vm/opto/macroArrayCopy.cpp +++ b/hotspot/src/share/vm/opto/macroArrayCopy.cpp @@ -880,8 +880,14 @@ bool PhaseMacroExpand::generate_block_arraycopy(Node** ctrl, MergeMemNode** mem, Node* sptr = basic_plus_adr(src, src_off); Node* dptr = basic_plus_adr(dest, dest_off); uint alias_idx = C->get_alias_index(adr_type); - Node* sval = transform_later(LoadNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), sptr, adr_type, TypeInt::INT, T_INT, MemNode::unordered)); - Node* st = transform_later(StoreNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), dptr, adr_type, sval, T_INT, MemNode::unordered)); + bool is_mismatched = (basic_elem_type != T_INT); + Node* sval = transform_later( + LoadNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), sptr, adr_type, + TypeInt::INT, T_INT, MemNode::unordered, LoadNode::DependsOnlyOnTest, + false /*unaligned*/, is_mismatched)); + Node* st = transform_later( + StoreNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), dptr, adr_type, + sval, T_INT, MemNode::unordered)); (*mem)->set_memory_at(alias_idx, st); src_off += BytesPerInt; dest_off += BytesPerInt; diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 2d2b40d334e..51733c8fa65 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -1582,7 +1582,6 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls, return NULL; } -#ifdef ASSERT static bool is_mismatched_access(ciConstant con, BasicType loadbt) { BasicType conbt = con.basic_type(); switch (conbt) { @@ -1597,7 +1596,6 @@ static bool is_mismatched_access(ciConstant con, BasicType loadbt) { } return (conbt != loadbt); } -#endif // ASSERT // Try to constant-fold a stable array element. static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) { @@ -1608,10 +1606,11 @@ static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicTyp ciArray* aobj = ary->const_oop()->as_array(); ciConstant con = aobj->element_value_by_offset(off); if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) { - assert(!is_mismatched_access(con, loadbt), - "conbt=%s; loadbt=%s", type2name(con.basic_type()), type2name(loadbt)); + bool is_mismatched = is_mismatched_access(con, loadbt); + assert(!is_mismatched, "conbt=%s; loadbt=%s", type2name(con.basic_type()), type2name(loadbt)); const Type* con_type = Type::make_from_constant(con); - if (con_type != NULL) { + // Guard against erroneous constant folding. + if (!is_mismatched && con_type != NULL) { if (con_type->isa_aryptr()) { // Join with the array element type, in case it is also stable. int dim = ary->stable_dimension(); From 57494c431d51ba2a87f218fa2bdb7ef9c188d469 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 11 Mar 2016 15:30:20 -0800 Subject: [PATCH 096/183] 8151750: Mark ChangingInterests.java as intermittently failing Reviewed-by: lancea --- jdk/test/java/nio/channels/Selector/ChangingInterests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jdk/test/java/nio/channels/Selector/ChangingInterests.java b/jdk/test/java/nio/channels/Selector/ChangingInterests.java index c3e1dbd0964..bd8ab27a1b5 100644 --- a/jdk/test/java/nio/channels/Selector/ChangingInterests.java +++ b/jdk/test/java/nio/channels/Selector/ChangingInterests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ /* @test * @bug 7200742 + * @key intermittent * @summary Test that Selector doesn't spin when changing interest ops */ From 1c1cec5a6f54edfab2c4f5c5ffc6c1309e15c7d3 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Fri, 11 Mar 2016 17:07:57 -0800 Subject: [PATCH 097/183] 8151734: Mark Unreachable.java and MaxRetries.java as intermittently failing Reviewed-by: weijun --- jdk/test/sun/security/krb5/auto/MaxRetries.java | 3 ++- jdk/test/sun/security/krb5/auto/Unreachable.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/jdk/test/sun/security/krb5/auto/MaxRetries.java b/jdk/test/sun/security/krb5/auto/MaxRetries.java index 5c5da91653f..d23cd1043b5 100644 --- a/jdk/test/sun/security/krb5/auto/MaxRetries.java +++ b/jdk/test/sun/security/krb5/auto/MaxRetries.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, 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 @@ -24,6 +24,7 @@ /* * @test * @bug 6844193 + * @key intermittent * @compile -XDignore.symbol.file MaxRetries.java * @run main/othervm/timeout=300 MaxRetries * @summary support max_retries in krb5.conf diff --git a/jdk/test/sun/security/krb5/auto/Unreachable.java b/jdk/test/sun/security/krb5/auto/Unreachable.java index 52339786a9f..b010b54837e 100644 --- a/jdk/test/sun/security/krb5/auto/Unreachable.java +++ b/jdk/test/sun/security/krb5/auto/Unreachable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, 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 @@ -24,6 +24,7 @@ /* * @test * @bug 7162687 + * @key intermittent * @summary enhance KDC server availability detection * @compile -XDignore.symbol.file Unreachable.java * @run main/othervm/timeout=10 Unreachable From bfb7e8cd0755d7c2a4411afa999e786eb97a8319 Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Sun, 13 Mar 2016 20:26:29 +0100 Subject: [PATCH 098/183] 8150782: findClass / accessClass throw unexpected exceptions Reviewed-by: sundar --- .../java/lang/invoke/MethodHandles.java | 19 +++- .../lang/invoke/t8150782/TestAccessClass.java | 80 +++++++++++++++++ .../java/lang/invoke/t8150782/TestCls.java | 38 ++++++++ .../lang/invoke/t8150782/TestFindClass.java | 90 +++++++++++++++++++ .../java/lang/invoke/t8150782/TestLookup.java | 67 ++++++++++++++ 5 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 jdk/test/java/lang/invoke/t8150782/TestAccessClass.java create mode 100644 jdk/test/java/lang/invoke/t8150782/TestCls.java create mode 100644 jdk/test/java/lang/invoke/t8150782/TestFindClass.java create mode 100644 jdk/test/java/lang/invoke/t8150782/TestLookup.java diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 70791273212..dea7d6c6c14 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -99,13 +99,16 @@ public class MethodHandles { *

* As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class} * of this lookup object will be {@link java.lang.Object}. + * Consequently, the lookup context of this lookup object will be the bootstrap + * class loader, which means it cannot find user classes. * *

* Discussion: * The lookup class can be changed to any other class {@code C} using an expression of the form * {@link Lookup#in publicLookup().in(C.class)}. * Since all classes have equal access to public names, - * such a change would confer no new access rights. + * such a change would confer no new access rights, + * but may change the lookup context by virtue of changing the class loader. * A public lookup object is always subject to * security manager checks. * Also, it cannot access @@ -641,6 +644,11 @@ public class MethodHandles { * then no members, not even public members, will be accessible. * (In all other cases, public members will continue to be accessible.) * + *

+ * The resulting lookup's capabilities for loading classes + * (used during {@link #findClass} invocations) + * are determined by the lookup class' loader, + * which may change due to this operation. * * @param requestedLookupClass the desired lookup class for the new lookup object * @return a lookup object which reports the desired lookup class @@ -939,13 +947,17 @@ assertEquals("[x, y, z]", pb.command().toString()); /** * Looks up a class by name from the lookup context defined by this {@code Lookup} object. The static * initializer of the class is not run. + *

+ * The lookup context here is determined by the {@linkplain #lookupClass() lookup class}, its class + * loader, and the {@linkplain #lookupModes() lookup modes}. In particular, the method first attempts to + * load the requested class, and then determines whether the class is accessible to this lookup object. * * @param targetName the fully qualified name of the class to be looked up. * @return the requested class. * @exception SecurityException if a security manager is present and it * refuses access * @throws LinkageError if the linkage fails - * @throws ClassNotFoundException if the class does not exist. + * @throws ClassNotFoundException if the class cannot be loaded by the lookup class' loader. * @throws IllegalAccessException if the class is not accessible, using the allowed access * modes. * @exception SecurityException if a security manager is present and it @@ -960,6 +972,9 @@ assertEquals("[x, y, z]", pb.command().toString()); /** * Determines if a class can be accessed from the lookup context defined by this {@code Lookup} object. The * static initializer of the class is not run. + *

+ * The lookup context here is determined by the {@linkplain #lookupClass() lookup class} and the + * {@linkplain #lookupModes() lookup modes}. * * @param targetClass the class to be access-checked * diff --git a/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java b/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java new file mode 100644 index 00000000000..5acf3f3bee0 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, 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. + */ + +/* @test + * @compile TestAccessClass.java TestCls.java + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestAccessClass + */ +package test.java.lang.invoke.t8150782; + +import java.lang.invoke.*; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +import org.testng.annotations.*; + +public class TestAccessClass { + + private static boolean initializedClass1; + + private static class Class1 { + static { + initializedClass1 = true; + } + } + + @Test + public void initializerNotRun() throws IllegalAccessException { + lookup().accessClass(Class1.class); + assertFalse(initializedClass1); + } + + @Test + public void returnsSameClass() throws IllegalAccessException, ClassNotFoundException { + Class aClass = lookup().accessClass(Class1.class); + assertEquals(Class1.class, aClass); + } + + @DataProvider + Object[][] illegalAccessAccess() { + return new Object[][] { + {publicLookup(), Class1.class}, + {publicLookup(), TestCls.getPrivateSIC()} + }; + } + + @Test(dataProvider = "illegalAccessAccess", expectedExceptions = {IllegalAccessException.class}) + public void illegalAccessExceptionTest(Lookup lookup, Class klass) throws IllegalAccessException, ClassNotFoundException { + lookup.accessClass(klass); + } + + @Test + public void okAccess() throws IllegalAccessException { + lookup().accessClass(TestCls.getPrivateSIC()); + } + +} diff --git a/jdk/test/java/lang/invoke/t8150782/TestCls.java b/jdk/test/java/lang/invoke/t8150782/TestCls.java new file mode 100644 index 00000000000..1aec2657d0a --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestCls.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016, 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 test.java.lang.invoke.t8150782; + +import static java.lang.invoke.MethodHandles.*; + +public class TestCls { + + public static final Lookup LOOKUP = lookup(); + + private static class PrivateSIC {} + public static Class getPrivateSIC() { return PrivateSIC.class; } + public static Lookup getLookupForPrivateSIC() { return lookup(); } + +} + diff --git a/jdk/test/java/lang/invoke/t8150782/TestFindClass.java b/jdk/test/java/lang/invoke/t8150782/TestFindClass.java new file mode 100644 index 00000000000..b49118c2b16 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestFindClass.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016, 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. + */ + +/* @test + * @compile TestFindClass.java TestCls.java + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestFindClass + */ +package test.java.lang.invoke.t8150782; + +import java.lang.invoke.*; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +import org.testng.annotations.*; + +public class TestFindClass { + + private static final String PACKAGE_PREFIX = "test.java.lang.invoke.t8150782."; + + private static boolean initializedClass1; + + private static class Class1 { + static { + initializedClass1 = true; + } + } + + @Test + public void initializerNotRun() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestFindClass$Class1"); + assertFalse(initializedClass1); + } + + @Test + public void returnsRequestedClass() throws IllegalAccessException, ClassNotFoundException { + Class aClass = lookup().findClass(PACKAGE_PREFIX + "TestFindClass$Class1"); + assertEquals(Class1.class, aClass); + } + + @Test(expectedExceptions = {ClassNotFoundException.class}) + public void classNotFoundExceptionTest() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestFindClass$NonExistent"); + } + + @DataProvider + Object[][] illegalAccessFind() { + return new Object[][] { + {publicLookup(), PACKAGE_PREFIX + "TestFindClass$Class1"}, + {publicLookup(), PACKAGE_PREFIX + "TestCls$PrivateSIC"} + }; + } + + /** + * Assertion: @throws IllegalAccessException if the class is not accessible, using the allowed access modes. + */ + @Test(dataProvider = "illegalAccessFind", expectedExceptions = {ClassNotFoundException.class}) + public void illegalAccessExceptionTest(Lookup lookup, String className) throws IllegalAccessException, ClassNotFoundException { + lookup.findClass(className); + } + + @Test + public void okAccess() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestCls$PrivateSIC"); + } + +} diff --git a/jdk/test/java/lang/invoke/t8150782/TestLookup.java b/jdk/test/java/lang/invoke/t8150782/TestLookup.java new file mode 100644 index 00000000000..9a3e2cd9085 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestLookup.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016, 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. + */ + +/* @test + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestLookup + */ +package test.java.lang.invoke.t8150782; + +import org.testng.annotations.Test; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +public class TestLookup { + + @Test + public void testClassLoaderChange() { + Lookup lookup = lookup(); + assertNotNull(lookup.lookupClass().getClassLoader()); + Lookup lookup2 = lookup.in(Object.class); + assertNull(lookup2.lookupClass().getClassLoader()); + } + + @Test(expectedExceptions = {ClassNotFoundException.class}) + public void testPublicCannotLoadUserClass() throws IllegalAccessException, ClassNotFoundException { + Lookup lookup = publicLookup(); + lookup.findClass("test.java.lang.invoke.t8150782.TestCls"); + } + + @Test + public void testPublicCanLoadSystemClass() throws IllegalAccessException, ClassNotFoundException { + Lookup lookup = publicLookup(); + lookup.findClass("java.util.HashMap"); + } + + @Test + public void testPublicInChangesClassLoader() { + Lookup lookup = publicLookup(); + assertNull(lookup.lookupClass().getClassLoader()); + Lookup lookup2 = lookup.in(TestCls.class); + assertNotNull(lookup2.lookupClass().getClassLoader()); + } + +} From cc3d80e38ac213233aa69b468597cf46e90c3857 Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Mon, 14 Mar 2016 08:10:44 +0100 Subject: [PATCH 099/183] 8151778: TestLookup.java fails after push of JDK-8150782 Reviewed-by: darcy --- jdk/test/java/lang/invoke/t8150782/TestLookup.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/test/java/lang/invoke/t8150782/TestLookup.java b/jdk/test/java/lang/invoke/t8150782/TestLookup.java index 9a3e2cd9085..833ac70f254 100644 --- a/jdk/test/java/lang/invoke/t8150782/TestLookup.java +++ b/jdk/test/java/lang/invoke/t8150782/TestLookup.java @@ -24,6 +24,7 @@ */ /* @test + * @compile TestLookup.java TestCls.java * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestLookup */ package test.java.lang.invoke.t8150782; From c53d88d41f668950d44ef7c4f1059c43ea9dab8f Mon Sep 17 00:00:00 2001 From: Amy Lu Date: Mon, 14 Mar 2016 19:46:19 +0800 Subject: [PATCH 100/183] 8151798: Mark java/util/TimeZone/Bug6772689.java as intermittently failing and demote to tier2 Reviewed-by: lancea --- jdk/test/TEST.groups | 2 ++ jdk/test/java/util/TimeZone/Bug6772689.java | 1 + 2 files changed, 3 insertions(+) diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index ea9a6d6fa7e..8b3a337c346 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -32,6 +32,7 @@ tier1 = \ -java/util/WeakHashMap/GCDuringIteration.java \ -java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \ -java/util/concurrent/forkjoin/FJExceptionTableLeak.java \ + -java/util/TimeZone/Bug6772689.java \ sun/nio/cs/ISO8859x.java \ java/nio/Buffer \ com/sun/crypto/provider/Cipher \ @@ -42,6 +43,7 @@ tier2 = \ java/util/WeakHashMap/GCDuringIteration.java \ java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \ java/util/concurrent/forkjoin/FJExceptionTableLeak.java \ + java/util/TimeZone/Bug6772689.java \ :jdk_io \ :jdk_nio \ -sun/nio/cs/ISO8859x.java \ diff --git a/jdk/test/java/util/TimeZone/Bug6772689.java b/jdk/test/java/util/TimeZone/Bug6772689.java index f730567013d..a1ce49682b4 100644 --- a/jdk/test/java/util/TimeZone/Bug6772689.java +++ b/jdk/test/java/util/TimeZone/Bug6772689.java @@ -24,6 +24,7 @@ /* * @test * @bug 6772689 + * @key intermittent * @summary Test for standard-to-daylight transitions at midnight: * date stays on the given day. */ From c6a6f496a86de67082b1535c5e0053bf27ec45de Mon Sep 17 00:00:00 2001 From: Abhijit Roy Date: Sat, 12 Mar 2016 00:58:39 +0530 Subject: [PATCH 101/183] 8151062: Unclosed parenthesis in java.util.EnumMap.clone() Javadoc Reviewed-by: rriggs --- jdk/src/java.base/share/classes/java/util/EnumMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/java/util/EnumMap.java b/jdk/src/java.base/share/classes/java/util/EnumMap.java index 686a0a9b98e..e6d63cf4ae8 100644 --- a/jdk/src/java.base/share/classes/java/util/EnumMap.java +++ b/jdk/src/java.base/share/classes/java/util/EnumMap.java @@ -718,7 +718,7 @@ public class EnumMap, V> extends AbstractMap } /** - * Returns a shallow copy of this enum map. (The values themselves + * Returns a shallow copy of this enum map. The values themselves * are not cloned. * * @return a shallow copy of this enum map From 887760ee885c5aa796e625e356f67a501f6f65ec Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 14 Mar 2016 10:48:18 -0700 Subject: [PATCH 102/183] 8151835: Mark SmallPrimeExponentP.java as intermittently failing Reviewed-by: vinnie --- jdk/test/sun/security/mscapi/SmallPrimeExponentP.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java b/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java index 1ee0f5bb069..0013bd86e03 100644 --- a/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java +++ b/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java @@ -32,6 +32,7 @@ import java.security.interfaces.RSAPrivateCrtKey; /* * @test * @bug 8023546 + * @key intermittent * @modules java.base/sun.security.x509 * java.base/sun.security.tools.keytool * @summary sun/security/mscapi/ShortRSAKey1024.sh fails intermittently From 04c17721d6d45ba7426ff63f0f76f23a39dbccc3 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Mon, 14 Mar 2016 16:13:09 -0700 Subject: [PATCH 103/183] 8151847: rmic should support v53 classfiles Reviewed-by: alanb --- .../share/classes/sun/tools/java/RuntimeConstants.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/jdk.rmic/share/classes/sun/tools/java/RuntimeConstants.java b/jdk/src/jdk.rmic/share/classes/sun/tools/java/RuntimeConstants.java index 87fa33f6197..1c7ada16f06 100644 --- a/jdk/src/jdk.rmic/share/classes/sun/tools/java/RuntimeConstants.java +++ b/jdk/src/jdk.rmic/share/classes/sun/tools/java/RuntimeConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, 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 @@ -67,7 +67,7 @@ public interface RuntimeConstants { /* Class File Constants */ int JAVA_MAGIC = 0xcafebabe; int JAVA_MIN_SUPPORTED_VERSION = 45; - int JAVA_MAX_SUPPORTED_VERSION = 52; + int JAVA_MAX_SUPPORTED_VERSION = 53; int JAVA_MAX_SUPPORTED_MINOR_VERSION = 0; /* Generate class file version for 1.1 by default */ From 569de7b0ea85f9bd95e0bc53966f329f60a9dfec Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 15 Mar 2016 12:38:35 +0800 Subject: [PATCH 104/183] 8151785: Doc typo in src/../java/util/stream/PipelineHelper.java Change from "intoWrapped" to "copyInto". Reviewed-by: rriggs --- .../share/classes/java/util/stream/PipelineHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java b/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java index 081f68d1a0e..8d989930386 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java +++ b/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java @@ -98,7 +98,7 @@ abstract class PipelineHelper { * @implSpec * The implementation behaves as if: *

{@code
-     *     intoWrapped(wrapSink(sink), spliterator);
+     *     copyInto(wrapSink(sink), spliterator);
      * }
* * @param sink the {@code Sink} to receive the results From 99bfb14042e8d9ba3aa28dcdd015e0a2042f0a5f Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Tue, 1 Mar 2016 12:33:04 -0800 Subject: [PATCH 105/183] 8147755: ASM should create correct constant tag for invokestatic on handle point to interface static method Updates asm to v5.1 Reviewed-by: forax --- .../org/objectweb/asm/ClassReader.java | 27 +- .../org/objectweb/asm/ClassWriter.java | 47 +- .../jdk/internal/org/objectweb/asm/Frame.java | 2 +- .../internal/org/objectweb/asm/Handle.java | 60 +- .../jdk/internal/org/objectweb/asm/Label.java | 9 +- .../org/objectweb/asm/MethodVisitor.java | 19 +- .../org/objectweb/asm/MethodWriter.java | 14 +- .../jdk/internal/org/objectweb/asm/Type.java | 14 +- .../internal/org/objectweb/asm/TypePath.java | 8 +- .../org/objectweb/asm/TypeReference.java | 44 +- .../objectweb/asm/commons/AdviceAdapter.java | 4 +- .../asm/commons/AnnotationRemapper.java | 108 +++ .../objectweb/asm/commons/ClassRemapper.java | 161 ++++ .../objectweb/asm/commons/FieldRemapper.java | 100 +++ .../asm/commons/InstructionAdapter.java | 2 +- .../asm/commons/LocalVariablesSorter.java | 14 - .../objectweb/asm/commons/MethodRemapper.java | 252 ++++++ .../org/objectweb/asm/commons/Remapper.java | 23 +- .../commons/RemappingAnnotationAdapter.java | 2 + .../asm/commons/RemappingClassAdapter.java | 2 + .../asm/commons/RemappingFieldAdapter.java | 2 + .../asm/commons/RemappingMethodAdapter.java | 2 + .../commons/RemappingSignatureAdapter.java | 2 + .../asm/commons/SerialVersionUIDAdder.java | 7 +- .../asm/commons/SignatureRemapper.java | 188 +++++ .../objectweb/asm/commons/SimpleRemapper.java | 6 + .../asm/signature/SignatureVisitor.java | 8 +- .../asm/signature/SignatureWriter.java | 4 +- .../org/objectweb/asm/tree/InsnList.java | 3 + .../org/objectweb/asm/util/ASMifier.java | 12 +- .../asm/util/CheckMethodAdapter.java | 3 + .../org/objectweb/asm/util/Printer.java | 786 ++++++++++++++++-- .../objectweb/asm/util/TraceClassVisitor.java | 26 +- .../asm/util/TraceSignatureVisitor.java | 14 +- .../internal/org/objectweb/asm/version.txt | 8 +- 35 files changed, 1773 insertions(+), 210 deletions(-) create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java create mode 100644 jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java index c9bf9d30225..523851fd70a 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java @@ -1199,7 +1199,14 @@ public class ClassReader { if (labels[label] == null) { readLabel(label, labels).status |= Label.DEBUG; } - labels[label].line = readUnsignedShort(v + 12); + Label l = labels[label]; + while (l.line > 0) { + if (l.next == null) { + l.next = new Label(); + } + l = l.next; + } + l.line = readUnsignedShort(v + 12); v += 4; } } @@ -1314,9 +1321,15 @@ public class ClassReader { // visits the label and line number for this offset, if any Label l = labels[offset]; if (l != null) { + Label next = l.next; + l.next = null; mv.visitLabel(l); if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) { mv.visitLineNumber(l.line, l); + while (next != null) { + mv.visitLineNumber(next.line, l); + next = next.next; + } } } @@ -1857,8 +1870,7 @@ public class ClassReader { v += 2; break; case 'B': // pointer to CONSTANT_Byte - av.visit(name, - (byte) readInt(items[readUnsignedShort(v)])); + av.visit(name, (byte) readInt(items[readUnsignedShort(v)])); v += 2; break; case 'Z': // pointer to CONSTANT_Boolean @@ -1868,13 +1880,11 @@ public class ClassReader { v += 2; break; case 'S': // pointer to CONSTANT_Short - av.visit(name, - (short) readInt(items[readUnsignedShort(v)])); + av.visit(name, (short) readInt(items[readUnsignedShort(v)])); v += 2; break; case 'C': // pointer to CONSTANT_Char - av.visit(name, - (char) readInt(items[readUnsignedShort(v)])); + av.visit(name, (char) readInt(items[readUnsignedShort(v)])); v += 2; break; case 's': // pointer to CONSTANT_Utf8 @@ -2515,11 +2525,12 @@ public class ClassReader { int tag = readByte(index); int[] items = this.items; int cpIndex = items[readUnsignedShort(index + 1)]; + boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; String owner = readClass(cpIndex, buf); cpIndex = items[readUnsignedShort(cpIndex + 2)]; String name = readUTF8(cpIndex, buf); String desc = readUTF8(cpIndex + 2, buf); - return new Handle(tag, owner, name, desc); + return new Handle(tag, owner, name, desc, itf); } } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java index f5b24254ece..2e3d62b0369 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java @@ -1081,7 +1081,7 @@ public class ClassWriter extends ClassVisitor { } } else if (cst instanceof Handle) { Handle h = (Handle) cst; - return newHandleItem(h.tag, h.owner, h.name, h.desc); + return newHandleItem(h.tag, h.owner, h.name, h.desc, h.itf); } else { throw new IllegalArgumentException("value " + cst); } @@ -1216,10 +1216,12 @@ public class ClassWriter extends ClassVisitor { * the name of the field or method. * @param desc * the descriptor of the field or method. + * @param itf + * true if the owner is an interface. * @return a new or an already existing method type reference item. */ Item newHandleItem(final int tag, final String owner, final String name, - final String desc) { + final String desc, final boolean itf) { key4.set(HANDLE_BASE + tag, owner, name, desc); Item result = get(key4); if (result == null) { @@ -1228,8 +1230,7 @@ public class ClassWriter extends ClassVisitor { } else { put112(HANDLE, tag, - newMethod(owner, name, desc, - tag == Opcodes.H_INVOKEINTERFACE)); + newMethod(owner, name, desc, itf)); } result = new Item(index++, key4); put(result); @@ -1259,10 +1260,44 @@ public class ClassWriter extends ClassVisitor { * the descriptor of the field or method. * @return the index of a new or already existing method type reference * item. + * + * @deprecated this method is superseded by + * {@link #newHandle(int, String, String, String, boolean)}. */ + @Deprecated public int newHandle(final int tag, final String owner, final String name, final String desc) { - return newHandleItem(tag, owner, name, desc).index; + return newHandle(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE); + } + + /** + * Adds a handle to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters. + * + * @param tag + * the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, + * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, + * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner + * the internal name of the field or method owner class. + * @param name + * the name of the field or method. + * @param desc + * the descriptor of the field or method. + * @param itf + * true if the owner is an interface. + * @return the index of a new or already existing method type reference + * item. + */ + public int newHandle(final int tag, final String owner, final String name, + final String desc, final boolean itf) { + return newHandleItem(tag, owner, name, desc, itf).index; } /** @@ -1294,7 +1329,7 @@ public class ClassWriter extends ClassVisitor { int hashCode = bsm.hashCode(); bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, - bsm.desc)); + bsm.desc, bsm.isInterface())); int argsLength = bsmArgs.length; bootstrapMethods.putShort(argsLength); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java index bb7ff8f5147..811b74c7242 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java @@ -192,7 +192,7 @@ final class Frame { private static final int LOCAL = 0x2000000; /** - * Kind of the types that are relative to the stack of an input stack + * Kind of the the types that are relative to the stack of an input stack * map frame. The value of such types is a position relatively to the top of * this stack. */ diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java index e8b2859b05d..407c1d99774 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java @@ -93,6 +93,12 @@ public final class Handle { */ final String desc; + + /** + * Indicate if the owner is an interface or not. + */ + final boolean itf; + /** * Constructs a new field or method handle. * @@ -113,12 +119,44 @@ public final class Handle { * @param desc * the descriptor of the field or method designated by this * handle. + * + * @deprecated this constructor has been superseded + * by {@link #Handle(int, String, String, String, boolean)}. */ + @Deprecated public Handle(int tag, String owner, String name, String desc) { + this(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE); + } + + /** + * Constructs a new field or method handle. + * + * @param tag + * the kind of field or method designated by this Handle. Must be + * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, + * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, + * {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner + * the internal name of the class that owns the field or method + * designated by this handle. + * @param name + * the name of the field or method designated by this handle. + * @param desc + * the descriptor of the field or method designated by this + * handle. + * @param itf + * true if the owner is an interface. + */ + public Handle(int tag, String owner, String name, String desc, boolean itf) { this.tag = tag; this.owner = owner; this.name = name; this.desc = desc; + this.itf = itf; } /** @@ -164,6 +202,17 @@ public final class Handle { return desc; } + /** + * Returns true if the owner of the field or method designated + * by this handle is an interface. + * + * @return true if the owner of the field or method designated + * by this handle is an interface. + */ + public boolean isInterface() { + return itf; + } + @Override public boolean equals(Object obj) { if (obj == this) { @@ -173,13 +222,13 @@ public final class Handle { return false; } Handle h = (Handle) obj; - return tag == h.tag && owner.equals(h.owner) && name.equals(h.name) - && desc.equals(h.desc); + return tag == h.tag && itf == h.itf && owner.equals(h.owner) + && name.equals(h.name) && desc.equals(h.desc); } @Override public int hashCode() { - return tag + owner.hashCode() * name.hashCode() * desc.hashCode(); + return tag + (itf? 64: 0) + owner.hashCode() * name.hashCode() * desc.hashCode(); } /** @@ -187,13 +236,16 @@ public final class Handle { * representation is: * *
+     * for a reference to a class:
      * owner '.' name desc ' ' '(' tag ')'
+     * for a reference to an interface:
+     * owner '.' name desc ' ' '(' tag ' ' itf ')'
      * 
* * . As this format is unambiguous, it can be parsed if necessary. */ @Override public String toString() { - return owner + '.' + name + desc + " (" + tag + ')'; + return owner + '.' + name + desc + " (" + tag + (itf? " itf": "") + ')'; } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java index bbea0001235..63e42a020bc 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java @@ -160,7 +160,11 @@ public class Label { int status; /** - * The line number corresponding to this label, if known. + * The line number corresponding to this label, if known. If there are + * several lines, each line is stored in a separate label, all linked via + * their next field (these links are created in ClassReader and removed just + * before visitLabel is called, so that this does not impact the rest of the + * code). */ int line; @@ -268,7 +272,8 @@ public class Label { * The next basic block in the basic block stack. This stack is used in the * main loop of the fix point algorithm used in the second step of the * control flow analysis algorithms. It is also used in - * {@link #visitSubroutine} to avoid using a recursive method. + * {@link #visitSubroutine} to avoid using a recursive method, and in + * ClassReader to temporarily store multiple source lines for a label. * * @see MethodWriter#visitMaxs */ diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java index 0bb1a05b805..1448067a467 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java @@ -62,15 +62,16 @@ package jdk.internal.org.objectweb.asm; * A visitor to visit a Java method. The methods of this class must be called in * the following order: ( visitParameter )* [ * visitAnnotationDefault ] ( visitAnnotation | - * visitTypeAnnotation | visitAttribute )* [ - * visitCode ( visitFrame | visitXInsn | - * visitLabel | visitInsnAnnotation | - * visitTryCatchBlock | visitTryCatchBlockAnnotation | - * visitLocalVariable | visitLocalVariableAnnotation | - * visitLineNumber )* visitMaxs ] visitEnd. In - * addition, the visitXInsn and visitLabel methods must - * be called in the sequential order of the bytecode instructions of the visited - * code, visitInsnAnnotation must be called after the annotated + * visitParameterAnnotation visitTypeAnnotation | + * visitAttribute )* [ visitCode ( visitFrame | + * visitXInsn | visitLabel | + * visitInsnAnnotation | visitTryCatchBlock | + * visitTryCatchAnnotation | visitLocalVariable | + * visitLocalVariableAnnotation | visitLineNumber )* + * visitMaxs ] visitEnd. In addition, the + * visitXInsn and visitLabel methods must be called in + * the sequential order of the bytecode instructions of the visited code, + * visitInsnAnnotation must be called after the annotated * instruction, visitTryCatchBlock must be called before the * labels passed as arguments have been visited, * visitTryCatchBlockAnnotation must be called after the diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java index e02fad465d9..c2e4031e304 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java @@ -2061,7 +2061,7 @@ class MethodWriter extends MethodVisitor { } int size = 8; if (code.length > 0) { - if (code.length > 65536) { + if (code.length > 65535) { throw new RuntimeException("Method code too large!"); } cw.newUTF8("Code"); @@ -2735,11 +2735,13 @@ class MethodWriter extends MethodVisitor { l = l.successor; } // Update the offsets in the uninitialized types - for (i = 0; i < cw.typeTable.length; ++i) { - Item item = cw.typeTable[i]; - if (item != null && item.type == ClassWriter.TYPE_UNINIT) { - item.intVal = getNewOffset(allIndexes, allSizes, 0, - item.intVal); + if (cw.typeTable != null) { + for (i = 0; i < cw.typeTable.length; ++i) { + Item item = cw.typeTable[i]; + if (item != null && item.type == ClassWriter.TYPE_UNINIT) { + item.intVal = getNewOffset(allIndexes, allSizes, 0, + item.intVal); + } } } // The stack map frames are not serialized yet, so we don't need diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java index 633a4a024ea..056ace15fa8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java @@ -654,7 +654,7 @@ public class Type { * @return the descriptor corresponding to this Java type. */ public String getDescriptor() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); getDescriptor(buf); return buf.toString(); } @@ -672,7 +672,7 @@ public class Type { */ public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append('('); for (int i = 0; i < argumentTypes.length; ++i) { argumentTypes[i].getDescriptor(buf); @@ -689,7 +689,7 @@ public class Type { * @param buf * the string buffer to which the descriptor must be appended. */ - private void getDescriptor(final StringBuffer buf) { + private void getDescriptor(final StringBuilder buf) { if (this.buf == null) { // descriptor is in byte 3 of 'off' for primitive types (buf == // null) @@ -729,7 +729,7 @@ public class Type { * @return the descriptor corresponding to the given class. */ public static String getDescriptor(final Class c) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); getDescriptor(buf, c); return buf.toString(); } @@ -743,7 +743,7 @@ public class Type { */ public static String getConstructorDescriptor(final Constructor c) { Class[] parameters = c.getParameterTypes(); - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append('('); for (int i = 0; i < parameters.length; ++i) { getDescriptor(buf, parameters[i]); @@ -760,7 +760,7 @@ public class Type { */ public static String getMethodDescriptor(final Method m) { Class[] parameters = m.getParameterTypes(); - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append('('); for (int i = 0; i < parameters.length; ++i) { getDescriptor(buf, parameters[i]); @@ -778,7 +778,7 @@ public class Type { * @param c * the class whose descriptor must be computed. */ - private static void getDescriptor(final StringBuffer buf, final Class c) { + private static void getDescriptor(final StringBuilder buf, final Class c) { Class d = c; while (true) { if (d.isPrimitive()) { diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java index a48a39d8b46..31fe2bc6826 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java @@ -71,25 +71,25 @@ public class TypePath { * A type path step that steps into the element type of an array type. See * {@link #getStep getStep}. */ - public static final int ARRAY_ELEMENT = 0; + public final static int ARRAY_ELEMENT = 0; /** * A type path step that steps into the nested type of a class type. See * {@link #getStep getStep}. */ - public static final int INNER_TYPE = 1; + public final static int INNER_TYPE = 1; /** * A type path step that steps into the bound of a wildcard type. See * {@link #getStep getStep}. */ - public static final int WILDCARD_BOUND = 2; + public final static int WILDCARD_BOUND = 2; /** * A type path step that steps into a type argument of a generic type. See * {@link #getStep getStep}. */ - public static final int TYPE_ARGUMENT = 3; + public final static int TYPE_ARGUMENT = 3; /** * The byte array where the path is stored, in Java class file format. diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java index b366df0afb7..4caf8f10db0 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java @@ -74,133 +74,133 @@ public class TypeReference { * The sort of type references that target a type parameter of a generic * class. See {@link #getSort getSort}. */ - public static final int CLASS_TYPE_PARAMETER = 0x00; + public final static int CLASS_TYPE_PARAMETER = 0x00; /** * The sort of type references that target a type parameter of a generic * method. See {@link #getSort getSort}. */ - public static final int METHOD_TYPE_PARAMETER = 0x01; + public final static int METHOD_TYPE_PARAMETER = 0x01; /** * The sort of type references that target the super class of a class or one * of the interfaces it implements. See {@link #getSort getSort}. */ - public static final int CLASS_EXTENDS = 0x10; + public final static int CLASS_EXTENDS = 0x10; /** * The sort of type references that target a bound of a type parameter of a * generic class. See {@link #getSort getSort}. */ - public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11; + public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11; /** * The sort of type references that target a bound of a type parameter of a * generic method. See {@link #getSort getSort}. */ - public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12; + public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12; /** * The sort of type references that target the type of a field. See * {@link #getSort getSort}. */ - public static final int FIELD = 0x13; + public final static int FIELD = 0x13; /** * The sort of type references that target the return type of a method. See * {@link #getSort getSort}. */ - public static final int METHOD_RETURN = 0x14; + public final static int METHOD_RETURN = 0x14; /** * The sort of type references that target the receiver type of a method. * See {@link #getSort getSort}. */ - public static final int METHOD_RECEIVER = 0x15; + public final static int METHOD_RECEIVER = 0x15; /** * The sort of type references that target the type of a formal parameter of * a method. See {@link #getSort getSort}. */ - public static final int METHOD_FORMAL_PARAMETER = 0x16; + public final static int METHOD_FORMAL_PARAMETER = 0x16; /** * The sort of type references that target the type of an exception declared * in the throws clause of a method. See {@link #getSort getSort}. */ - public static final int THROWS = 0x17; + public final static int THROWS = 0x17; /** * The sort of type references that target the type of a local variable in a * method. See {@link #getSort getSort}. */ - public static final int LOCAL_VARIABLE = 0x40; + public final static int LOCAL_VARIABLE = 0x40; /** * The sort of type references that target the type of a resource variable * in a method. See {@link #getSort getSort}. */ - public static final int RESOURCE_VARIABLE = 0x41; + public final static int RESOURCE_VARIABLE = 0x41; /** * The sort of type references that target the type of the exception of a * 'catch' clause in a method. See {@link #getSort getSort}. */ - public static final int EXCEPTION_PARAMETER = 0x42; + public final static int EXCEPTION_PARAMETER = 0x42; /** * The sort of type references that target the type declared in an * 'instanceof' instruction. See {@link #getSort getSort}. */ - public static final int INSTANCEOF = 0x43; + public final static int INSTANCEOF = 0x43; /** * The sort of type references that target the type of the object created by * a 'new' instruction. See {@link #getSort getSort}. */ - public static final int NEW = 0x44; + public final static int NEW = 0x44; /** * The sort of type references that target the receiver type of a * constructor reference. See {@link #getSort getSort}. */ - public static final int CONSTRUCTOR_REFERENCE = 0x45; + public final static int CONSTRUCTOR_REFERENCE = 0x45; /** * The sort of type references that target the receiver type of a method * reference. See {@link #getSort getSort}. */ - public static final int METHOD_REFERENCE = 0x46; + public final static int METHOD_REFERENCE = 0x46; /** * The sort of type references that target the type declared in an explicit * or implicit cast instruction. See {@link #getSort getSort}. */ - public static final int CAST = 0x47; + public final static int CAST = 0x47; /** * The sort of type references that target a type parameter of a generic * constructor in a constructor call. See {@link #getSort getSort}. */ - public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; + public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; /** * The sort of type references that target a type parameter of a generic * method in a method call. See {@link #getSort getSort}. */ - public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; + public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; /** * The sort of type references that target a type parameter of a generic * constructor in a constructor reference. See {@link #getSort getSort}. */ - public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; + public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; /** * The sort of type references that target a type parameter of a generic * method in a method reference. See {@link #getSort getSort}. */ - public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; + public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; /** * The type reference value in Java class file format. diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java index c07917784df..00dccd549f0 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java @@ -388,10 +388,10 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } break; case PUTFIELD: + popValue(); popValue(); if (longOrDouble) { popValue(); - popValue(); } break; // case GETFIELD: @@ -619,7 +619,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } /** - * Called at the beginning of the method or after super class class call in + * Called at the beginning of the method or after super class call in * the constructor.
*
* diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java new file mode 100644 index 00000000000..3482ac95f6c --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * An {@link AnnotationVisitor} adapter for type remapping. + * + * @author Eugene Kuleshov + */ +public class AnnotationRemapper extends AnnotationVisitor { + + protected final Remapper remapper; + + public AnnotationRemapper(final AnnotationVisitor av, + final Remapper remapper) { + this(Opcodes.ASM5, av, remapper); + } + + protected AnnotationRemapper(final int api, final AnnotationVisitor av, + final Remapper remapper) { + super(api, av); + this.remapper = remapper; + } + + @Override + public void visit(String name, Object value) { + av.visit(name, remapper.mapValue(value)); + } + + @Override + public void visitEnum(String name, String desc, String value) { + av.visitEnum(name, remapper.mapDesc(desc), value); + } + + @Override + public AnnotationVisitor visitAnnotation(String name, String desc) { + AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc)); + return v == null ? null : (v == av ? this : new AnnotationRemapper(v, + remapper)); + } + + @Override + public AnnotationVisitor visitArray(String name) { + AnnotationVisitor v = av.visitArray(name); + return v == null ? null : (v == av ? this : new AnnotationRemapper(v, + remapper)); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java new file mode 100644 index 00000000000..8a8ea738ae9 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java @@ -0,0 +1,161 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.TypePath; + +/** + * A {@link ClassVisitor} for type remapping. + * + * @author Eugene Kuleshov + */ +public class ClassRemapper extends ClassVisitor { + + protected final Remapper remapper; + + protected String className; + + public ClassRemapper(final ClassVisitor cv, final Remapper remapper) { + this(Opcodes.ASM5, cv, remapper); + } + + protected ClassRemapper(final int api, final ClassVisitor cv, + final Remapper remapper) { + super(api, cv); + this.remapper = remapper; + } + + @Override + public void visit(int version, int access, String name, String signature, + String superName, String[] interfaces) { + this.className = name; + super.visit(version, access, remapper.mapType(name), remapper + .mapSignature(signature, false), remapper.mapType(superName), + interfaces == null ? null : remapper.mapTypes(interfaces)); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), + visible); + return av == null ? null : createAnnotationRemapper(av); + } + + @Override + public AnnotationVisitor visitTypeAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? null : createAnnotationRemapper(av); + } + + @Override + public FieldVisitor visitField(int access, String name, String desc, + String signature, Object value) { + FieldVisitor fv = super.visitField(access, + remapper.mapFieldName(className, name, desc), + remapper.mapDesc(desc), remapper.mapSignature(signature, true), + remapper.mapValue(value)); + return fv == null ? null : createFieldRemapper(fv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { + String newDesc = remapper.mapMethodDesc(desc); + MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName( + className, name, desc), newDesc, remapper.mapSignature( + signature, false), + exceptions == null ? null : remapper.mapTypes(exceptions)); + return mv == null ? null : createMethodRemapper(mv); + } + + @Override + public void visitInnerClass(String name, String outerName, + String innerName, int access) { + // TODO should innerName be changed? + super.visitInnerClass(remapper.mapType(name), outerName == null ? null + : remapper.mapType(outerName), innerName, access); + } + + @Override + public void visitOuterClass(String owner, String name, String desc) { + super.visitOuterClass(remapper.mapType(owner), name == null ? null + : remapper.mapMethodName(owner, name, desc), + desc == null ? null : remapper.mapMethodDesc(desc)); + } + + protected FieldVisitor createFieldRemapper(FieldVisitor fv) { + return new FieldRemapper(fv, remapper); + } + + protected MethodVisitor createMethodRemapper(MethodVisitor mv) { + return new MethodRemapper(mv, remapper); + } + + protected AnnotationVisitor createAnnotationRemapper(AnnotationVisitor av) { + return new AnnotationRemapper(av, remapper); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java new file mode 100644 index 00000000000..13f8b7fd154 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.TypePath; + +/** + * A {@link FieldVisitor} adapter for type remapping. + * + * @author Eugene Kuleshov + */ +public class FieldRemapper extends FieldVisitor { + + private final Remapper remapper; + + public FieldRemapper(final FieldVisitor fv, final Remapper remapper) { + this(Opcodes.ASM5, fv, remapper); + } + + protected FieldRemapper(final int api, final FieldVisitor fv, + final Remapper remapper) { + super(api, fv); + this.remapper = remapper; + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc), + visible); + return av == null ? null : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitTypeAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? null : new AnnotationRemapper(av, remapper); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java index 8ecb1c9c4b1..2df144ef70c 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java @@ -73,7 +73,7 @@ import jdk.internal.org.objectweb.asm.Type; */ public class InstructionAdapter extends MethodVisitor { - public static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); + public final static Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); /** * Creates a new {@link InstructionAdapter}. Subclasses must not use this diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java index 5d02c53768d..7aad39658e8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java @@ -104,11 +104,6 @@ public class LocalVariablesSorter extends MethodVisitor { */ protected int nextLocal; - /** - * Indicates if at least one local variable has moved due to remapping. - */ - private boolean changed; - /** * Creates a new {@link LocalVariablesSorter}. Subclasses must not use * this constructor. Instead, they must use the @@ -228,11 +223,6 @@ public class LocalVariablesSorter extends MethodVisitor { "ClassReader.accept() should be called with EXPAND_FRAMES flag"); } - if (!changed) { // optimization for the case where mapping = identity - mv.visitFrame(type, nLocal, local, nStack, stack); - return; - } - // creates a copy of newLocals Object[] oldLocals = new Object[newLocals.length]; System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length); @@ -328,7 +318,6 @@ public class LocalVariablesSorter extends MethodVisitor { int local = newLocalMapping(type); setLocalType(local, type); setFrameLocal(local, t); - changed = true; return local; } @@ -396,9 +385,6 @@ public class LocalVariablesSorter extends MethodVisitor { } else { value--; } - if (value != var) { - changed = true; - } return value; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java new file mode 100644 index 00000000000..486cc6b7c57 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java @@ -0,0 +1,252 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.TypePath; + +/** + * A {@link LocalVariablesSorter} for type mapping. + * + * @author Eugene Kuleshov + */ +public class MethodRemapper extends MethodVisitor { + + protected final Remapper remapper; + + public MethodRemapper(final MethodVisitor mv, final Remapper remapper) { + this(Opcodes.ASM5, mv, remapper); + } + + protected MethodRemapper(final int api, final MethodVisitor mv, + final Remapper remapper) { + super(api, mv); + this.remapper = remapper; + } + + @Override + public AnnotationVisitor visitAnnotationDefault() { + AnnotationVisitor av = super.visitAnnotationDefault(); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), + visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitTypeAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitParameterAnnotation(int parameter, + String desc, boolean visible) { + AnnotationVisitor av = super.visitParameterAnnotation(parameter, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public void visitFrame(int type, int nLocal, Object[] local, int nStack, + Object[] stack) { + super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack, + remapEntries(nStack, stack)); + } + + private Object[] remapEntries(int n, Object[] entries) { + for (int i = 0; i < n; i++) { + if (entries[i] instanceof String) { + Object[] newEntries = new Object[n]; + if (i > 0) { + System.arraycopy(entries, 0, newEntries, 0, i); + } + do { + Object t = entries[i]; + newEntries[i++] = t instanceof String ? remapper + .mapType((String) t) : t; + } while (i < n); + return newEntries; + } + } + return entries; + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, + String desc) { + super.visitFieldInsn(opcode, remapper.mapType(owner), + remapper.mapFieldName(owner, name, desc), + remapper.mapDesc(desc)); + } + + @Deprecated + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, String owner, String name, + String desc, boolean itf) { + // Calling super.visitMethodInsn requires to call the correct version + // depending on this.api (otherwise infinite loops can occur). To + // simplify and to make it easier to automatically remove the backward + // compatibility code, we inline the code of the overridden method here. + // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN + // LocalVariableSorter. + if (mv != null) { + mv.visitMethodInsn(opcode, remapper.mapType(owner), + remapper.mapMethodName(owner, name, desc), + remapper.mapMethodDesc(desc), itf); + } + } + + @Override + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { + for (int i = 0; i < bsmArgs.length; i++) { + bsmArgs[i] = remapper.mapValue(bsmArgs[i]); + } + super.visitInvokeDynamicInsn( + remapper.mapInvokeDynamicMethodName(name, desc), + remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm), + bsmArgs); + } + + @Override + public void visitTypeInsn(int opcode, String type) { + super.visitTypeInsn(opcode, remapper.mapType(type)); + } + + @Override + public void visitLdcInsn(Object cst) { + super.visitLdcInsn(remapper.mapValue(cst)); + } + + @Override + public void visitMultiANewArrayInsn(String desc, int dims) { + super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims); + } + + @Override + public AnnotationVisitor visitInsnAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitInsnAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public void visitTryCatchBlock(Label start, Label end, Label handler, + String type) { + super.visitTryCatchBlock(start, end, handler, type == null ? null + : remapper.mapType(type)); + } + + @Override + public AnnotationVisitor visitTryCatchAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTryCatchAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public void visitLocalVariable(String name, String desc, String signature, + Label start, Label end, int index) { + super.visitLocalVariable(name, remapper.mapDesc(desc), + remapper.mapSignature(signature, true), start, end, index); + } + + @Override + public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, + TypePath typePath, Label[] start, Label[] end, int[] index, + String desc, boolean visible) { + AnnotationVisitor av = super.visitLocalVariableAnnotation(typeRef, + typePath, start, end, index, remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java index d5edd06363f..b90aee05590 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java @@ -168,17 +168,19 @@ public abstract class Remapper { Handle h = (Handle) value; return new Handle(h.getTag(), mapType(h.getOwner()), mapMethodName( h.getOwner(), h.getName(), h.getDesc()), - mapMethodDesc(h.getDesc())); + mapMethodDesc(h.getDesc()), h.isInterface()); } return value; } /** - * + * @param signature + * signature for mapper * @param typeSignature * true if signature is a FieldTypeSignature, such as the * signature parameter of the ClassVisitor.visitField or * MethodVisitor.visitLocalVariable methods + * @return signature rewritten as a string */ public String mapSignature(String signature, boolean typeSignature) { if (signature == null) { @@ -186,7 +188,7 @@ public abstract class Remapper { } SignatureReader r = new SignatureReader(signature); SignatureWriter w = new SignatureWriter(); - SignatureVisitor a = createRemappingSignatureAdapter(w); + SignatureVisitor a = createSignatureRemapper(w); if (typeSignature) { r.acceptType(a); } else { @@ -195,9 +197,18 @@ public abstract class Remapper { return w.toString(); } + /** + * @deprecated use {@link #createSignatureRemapper} instead. + */ + @Deprecated protected SignatureVisitor createRemappingSignatureAdapter( SignatureVisitor v) { - return new RemappingSignatureAdapter(v, this); + return new SignatureRemapper(v, this); + } + + protected SignatureVisitor createSignatureRemapper( + SignatureVisitor v) { + return createRemappingSignatureAdapter(v); } /** @@ -245,6 +256,10 @@ public abstract class Remapper { /** * Map type name to the new name. Subclasses can override. + * + * @param typeName + * the type name + * @return new name, default implementation is the identity. */ public String map(String typeName) { return typeName; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java index b9a1bc874aa..af0fe2b4fb4 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java @@ -65,8 +65,10 @@ import jdk.internal.org.objectweb.asm.Opcodes; /** * An {@link AnnotationVisitor} adapter for type remapping. * + * //@deprecated use {@link AnnotationRemapper} instead. * @author Eugene Kuleshov */ +//@Deprecated public class RemappingAnnotationAdapter extends AnnotationVisitor { protected final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java index 28b736be7a4..e36d79e931d 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java @@ -69,8 +69,10 @@ import jdk.internal.org.objectweb.asm.TypePath; /** * A {@link ClassVisitor} for type remapping. * + * @deprecated use {@link ClassRemapper} instead. * @author Eugene Kuleshov */ +@Deprecated public class RemappingClassAdapter extends ClassVisitor { protected final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java index 9d94e5ee327..8bafee1bf4a 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java @@ -67,8 +67,10 @@ import jdk.internal.org.objectweb.asm.TypePath; /** * A {@link FieldVisitor} adapter for type remapping. * + * @deprecated use {@link FieldRemapper} instead. * @author Eugene Kuleshov */ +@Deprecated public class RemappingFieldAdapter extends FieldVisitor { private final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java index d5493a1b1b5..f58963db6ef 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java @@ -69,8 +69,10 @@ import jdk.internal.org.objectweb.asm.TypePath; /** * A {@link LocalVariablesSorter} for type mapping. * + * //@deprecated use {@link MethodRemapper} instead. * @author Eugene Kuleshov */ +//@Deprecated public class RemappingMethodAdapter extends LocalVariablesSorter { protected final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java index 3b8ab02a3f1..4aa8428f344 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java @@ -65,8 +65,10 @@ import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; /** * A {@link SignatureVisitor} adapter for type mapping. * + * @deprecated use {@link SignatureRemapper} instead. * @author Eugene Kuleshov */ +@Deprecated public class RemappingSignatureAdapter extends SignatureVisitor { private final SignatureVisitor v; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java index cd407fd8063..0486710dd47 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java @@ -234,7 +234,7 @@ public class SerialVersionUIDAdder extends ClassVisitor { public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { - computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0; + computeSVUID = (access & Opcodes.ACC_ENUM) == 0; if (computeSVUID) { this.name = name; @@ -396,6 +396,11 @@ public class SerialVersionUIDAdder extends ClassVisitor { /* * 2. The class modifiers written as a 32-bit integer. */ + int access = this.access; + if ((access & Opcodes.ACC_INTERFACE) != 0) { + access = (svuidMethods.size() > 0) ? (access | Opcodes.ACC_ABSTRACT) + : (access & ~Opcodes.ACC_ABSTRACT); + } dos.writeInt(access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT)); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java new file mode 100644 index 00000000000..cf18f2bbb58 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java @@ -0,0 +1,188 @@ +/* + * 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. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import java.util.Stack; + +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; + +/** + * A {@link SignatureVisitor} adapter for type mapping. + * + * @author Eugene Kuleshov + */ +public class SignatureRemapper extends SignatureVisitor { + + private final SignatureVisitor v; + + private final Remapper remapper; + + private Stack classNames = new Stack(); + + public SignatureRemapper(final SignatureVisitor v, final Remapper remapper) { + this(Opcodes.ASM5, v, remapper); + } + + protected SignatureRemapper(final int api, final SignatureVisitor v, + final Remapper remapper) { + super(api); + this.v = v; + this.remapper = remapper; + } + + @Override + public void visitClassType(String name) { + classNames.push(name); + v.visitClassType(remapper.mapType(name)); + } + + @Override + public void visitInnerClassType(String name) { + String outerClassName = classNames.pop(); + String className = outerClassName + '$' + name; + classNames.push(className); + String remappedOuter = remapper.mapType(outerClassName) + '$'; + String remappedName = remapper.mapType(className); + int index = remappedName.startsWith(remappedOuter) ? remappedOuter + .length() : remappedName.lastIndexOf('$') + 1; + v.visitInnerClassType(remappedName.substring(index)); + } + + @Override + public void visitFormalTypeParameter(String name) { + v.visitFormalTypeParameter(name); + } + + @Override + public void visitTypeVariable(String name) { + v.visitTypeVariable(name); + } + + @Override + public SignatureVisitor visitArrayType() { + v.visitArrayType(); + return this; + } + + @Override + public void visitBaseType(char descriptor) { + v.visitBaseType(descriptor); + } + + @Override + public SignatureVisitor visitClassBound() { + v.visitClassBound(); + return this; + } + + @Override + public SignatureVisitor visitExceptionType() { + v.visitExceptionType(); + return this; + } + + @Override + public SignatureVisitor visitInterface() { + v.visitInterface(); + return this; + } + + @Override + public SignatureVisitor visitInterfaceBound() { + v.visitInterfaceBound(); + return this; + } + + @Override + public SignatureVisitor visitParameterType() { + v.visitParameterType(); + return this; + } + + @Override + public SignatureVisitor visitReturnType() { + v.visitReturnType(); + return this; + } + + @Override + public SignatureVisitor visitSuperclass() { + v.visitSuperclass(); + return this; + } + + @Override + public void visitTypeArgument() { + v.visitTypeArgument(); + } + + @Override + public SignatureVisitor visitTypeArgument(char wildcard) { + v.visitTypeArgument(wildcard); + return this; + } + + @Override + public void visitEnd() { + v.visitEnd(); + classNames.pop(); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java index 56b9bb57dcf..ebf59f4bf53 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java @@ -85,6 +85,12 @@ public class SimpleRemapper extends Remapper { return s == null ? name : s; } + @Override + public String mapInvokeDynamicMethodName(String name, String desc) { + String s = map('.' + name + desc); + return s == null ? name : s; + } + @Override public String mapFieldName(String owner, String name, String desc) { String s = map(owner + '.' + name); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java index 9114bcd348e..8ad2de61230 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java @@ -68,7 +68,7 @@ import jdk.internal.org.objectweb.asm.Opcodes; *