From 71681ac4cbac84c196b3b2ed482d1b608ae30ca2 Mon Sep 17 00:00:00 2001
From: Brian Burkhalter
Date: Mon, 1 Feb 2016 15:00:02 -0800
Subject: [PATCH 001/149] 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/149] 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:
*
* @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 DataBufferTYPEs.
+ * 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
- * ImageInputStreamstream, 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}
*
*
*
*
@@ -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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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/149] 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 3a1062775ada000b51703c3c38acaf5f7eab3bdf Mon Sep 17 00:00:00 2001
From: Andreas Eriksson
Date: Thu, 18 Feb 2016 16:15:15 +0100
Subject: [PATCH 048/149] 8149743: JVM crash after debugger hotswap with
lambdas
Reviewed-by: sspitsyn, coleenp, dcubed
---
.../com/sun/jdi/RedefineAddPrivateMethod.sh | 77 +++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100644 jdk/test/com/sun/jdi/RedefineAddPrivateMethod.sh
diff --git a/jdk/test/com/sun/jdi/RedefineAddPrivateMethod.sh b/jdk/test/com/sun/jdi/RedefineAddPrivateMethod.sh
new file mode 100644
index 00000000000..bb9eefd8968
--- /dev/null
+++ b/jdk/test/com/sun/jdi/RedefineAddPrivateMethod.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+#
+# 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 8149743
+# @summary crash when adding a breakpoint after redefining to add a private static method
+# @run shell RedefineAddPrivateMethod.sh
+
+compileOptions=-g
+
+createJavaFile()
+{
+ cat < $1.java.1
+public class $1 {
+ static public void main(String[] args) {
+ // @1 breakpoint @2 breakpoint
+ }
+
+ // @1 uncomment private static void test() {}
+}
+EOF
+}
+
+# This is called to feed cmds to jdb.
+dojdbCmds()
+{
+ setBkpts @1
+ runToBkpt @1
+ redefineClass @1
+ setBkpts @2
+ cmd allowExit cont
+}
+
+
+mysetup()
+{
+ if [ -z "$TESTSRC" ] ; then
+ TESTSRC=.
+ fi
+
+ for ii in . $TESTSRC $TESTSRC/.. ; do
+ if [ -r "$ii/ShellScaffold.sh" ] ; then
+ . $ii/ShellScaffold.sh
+ break
+ fi
+ done
+}
+
+# You could replace this next line with the contents
+# of ShellScaffold.sh and this script will run just the same.
+mysetup
+
+runit
+debuggeeFailIfPresent "Internal exception:"
+pass
From 35a916a2a186a093ef4c4b759edc1164793ef82a Mon Sep 17 00:00:00 2001
From: Andreas Eriksson
Date: Thu, 18 Feb 2016 16:15:28 +0100
Subject: [PATCH 049/149] 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 050/149] 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 051/149] 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 052/149] 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 053/149] 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 054/149] 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 ef5eb42e40bfd979df5b4acd6a77e71134f71a15 Mon Sep 17 00:00:00 2001
From: Aleksey Shipilev
Date: Tue, 23 Feb 2016 17:55:28 +0300
Subject: [PATCH 055/149] 8150180: String.value contents should be trusted
Reviewed-by: vlivanov, redestad, jrose, twisti
---
.../share/classes/java/lang/String.java | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/jdk/src/java.base/share/classes/java/lang/String.java b/jdk/src/java.base/share/classes/java/lang/String.java
index 86ec043d5b1..85d22cbc1ec 100644
--- a/jdk/src/java.base/share/classes/java/lang/String.java
+++ b/jdk/src/java.base/share/classes/java/lang/String.java
@@ -42,6 +42,7 @@ import java.util.regex.PatternSyntaxException;
import java.util.stream.IntStream;
import java.util.stream.StreamSupport;
import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.vm.annotation.Stable;
/**
* The {@code String} class represents character strings. All
@@ -119,7 +120,18 @@ import jdk.internal.HotSpotIntrinsicCandidate;
public final class String
implements java.io.Serializable, Comparable, CharSequence {
- /** The value is used for character storage. */
+ /**
+ * The value is used for character storage.
+ *
+ * @implNote This field is trusted by the VM, and is a subject to
+ * constant folding if String instance is constant. Overwriting this
+ * field after construction will cause problems.
+ *
+ * Additionally, it is marked with {@link Stable} to trust the contents
+ * of the array. No other facility in JDK provides this functionality (yet).
+ * {@link Stable} is safe here, because value is never null.
+ */
+ @Stable
private final byte[] value;
/**
@@ -129,6 +141,9 @@ public final class String
* LATIN1
* UTF16
*
+ * @implNote This field is trusted by the VM, and is a subject to
+ * constant folding if String instance is constant. Overwriting this
+ * field after construction will cause problems.
*/
private final byte coder;
From 7386fd03857982ae1ab216e8c093a5e17ae7229f Mon Sep 17 00:00:00 2001
From: Aleksey Shipilev
Date: Tue, 23 Feb 2016 22:10:02 +0300
Subject: [PATCH 056/149] 8148146: Integrate new internal Unsafe entry points,
and basic intrinsic support for VarHandles
Reviewed-by: psandoz, kvn, jrose, adinn, simonis, coleenp
---
.../classes/jdk/internal/misc/Unsafe.java | 355 ++++++++++++++++++
1 file changed, 355 insertions(+)
diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
index 5818d4835a1..8905977111b 100644
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
@@ -782,6 +782,46 @@ public final class Unsafe {
Object expected,
Object x);
+ @HotSpotIntrinsicCandidate
+ public final native Object compareAndExchangeObjectVolatile(Object o, long offset,
+ Object expected,
+ Object x);
+
+ @HotSpotIntrinsicCandidate
+ public final Object compareAndExchangeObjectAcquire(Object o, long offset,
+ Object expected,
+ Object x) {
+ return compareAndExchangeObjectVolatile(o, offset, expected, x);
+ }
+
+ @HotSpotIntrinsicCandidate
+ public final Object compareAndExchangeObjectRelease(Object o, long offset,
+ Object expected,
+ Object x) {
+ return compareAndExchangeObjectVolatile(o, offset, expected, x);
+ }
+
+ @HotSpotIntrinsicCandidate
+ public final boolean weakCompareAndSwapObject(Object o, long offset,
+ Object expected,
+ Object x) {
+ return compareAndSwapObject(o, offset, expected, x);
+ }
+
+ @HotSpotIntrinsicCandidate
+ public final boolean weakCompareAndSwapObjectAcquire(Object o, long offset,
+ Object expected,
+ Object x) {
+ return compareAndSwapObject(o, offset, expected, x);
+ }
+
+ @HotSpotIntrinsicCandidate
+ public final boolean weakCompareAndSwapObjectRelease(Object o, long offset,
+ Object expected,
+ Object x) {
+ return compareAndSwapObject(o, offset, expected, x);
+ }
+
/**
* Atomically updates Java variable to {@code x} if it is currently
* holding {@code expected}.
@@ -796,6 +836,46 @@ public final class Unsafe {
int expected,
int x);
+ @HotSpotIntrinsicCandidate
+ public final native int compareAndExchangeIntVolatile(Object o, long offset,
+ int expected,
+ int x);
+
+ @HotSpotIntrinsicCandidate
+ public final int compareAndExchangeIntAcquire(Object o, long offset,
+ int expected,
+ int x) {
+ return compareAndExchangeIntVolatile(o, offset, expected, x);
+ }
+
+ @HotSpotIntrinsicCandidate
+ public final int compareAndExchangeIntRelease(Object o, long offset,
+ int expected,
+ int x) {
+ return compareAndExchangeIntVolatile(o, offset, expected, x);
+ }
+
+ @HotSpotIntrinsicCandidate
+ public final boolean weakCompareAndSwapInt(Object o, long offset,
+ int expected,
+ int x) {
+ return compareAndSwapInt(o, offset, expected, x);
+ }
+
+ @HotSpotIntrinsicCandidate
+ public final boolean weakCompareAndSwapIntAcquire(Object o, long offset,
+ int expected,
+ int x) {
+ return compareAndSwapInt(o, offset, expected, x);
+ }
+
+ @HotSpotIntrinsicCandidate
+ public final boolean weakCompareAndSwapIntRelease(Object o, long offset,
+ int expected,
+ int x) {
+ return compareAndSwapInt(o, offset, expected, x);
+ }
+
/**
* Atomically updates Java variable to {@code x} if it is currently
* holding {@code expected}.
@@ -810,6 +890,46 @@ public final class Unsafe {
long expected,
long x);
+ @HotSpotIntrinsicCandidate
+ public final native long compareAndExchangeLongVolatile(Object o, long offset,
+ long expected,
+ long x);
+
+ @HotSpotIntrinsicCandidate
+ public final long compareAndExchangeLongAcquire(Object o, long offset,
+ long expected,
+ long x) {
+ return compareAndExchangeLongVolatile(o, offset, expected, x);
+ }
+
+ @HotSpotIntrinsicCandidate
+ public final long compareAndExchangeLongRelease(Object o, long offset,
+ long expected,
+ long x) {
+ return compareAndExchangeLongVolatile(o, offset, expected, x);
+ }
+
+ @HotSpotIntrinsicCandidate
+ public final boolean weakCompareAndSwapLong(Object o, long offset,
+ long expected,
+ long x) {
+ return compareAndSwapLong(o, offset, expected, x);
+ }
+
+ @HotSpotIntrinsicCandidate
+ public final boolean weakCompareAndSwapLongAcquire(Object o, long offset,
+ long expected,
+ long x) {
+ return compareAndSwapLong(o, offset, expected, x);
+ }
+
+ @HotSpotIntrinsicCandidate
+ public final boolean weakCompareAndSwapLongRelease(Object o, long offset,
+ long expected,
+ long x) {
+ return compareAndSwapLong(o, offset, expected, x);
+ }
+
/**
* Fetches a reference value from a given Java variable, with volatile
* load semantics. Otherwise identical to {@link #getObject(Object, long)}
@@ -908,6 +1028,224 @@ public final class Unsafe {
@HotSpotIntrinsicCandidate
public native void putOrderedLong(Object o, long offset, long x);
+ /** Acquire version of {@link #getObjectVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final Object getObjectAcquire(Object o, long offset) {
+ return getObjectVolatile(o, offset);
+ }
+
+ /** Acquire version of {@link #getBooleanVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final boolean getBooleanAcquire(Object o, long offset) {
+ return getBooleanVolatile(o, offset);
+ }
+
+ /** Acquire version of {@link #getByteVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final byte getByteAcquire(Object o, long offset) {
+ return getByteVolatile(o, offset);
+ }
+
+ /** Acquire version of {@link #getShortVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final short getShortAcquire(Object o, long offset) {
+ return getShortVolatile(o, offset);
+ }
+
+ /** Acquire version of {@link #getCharVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final char getCharAcquire(Object o, long offset) {
+ return getCharVolatile(o, offset);
+ }
+
+ /** Acquire version of {@link #getIntVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final int getIntAcquire(Object o, long offset) {
+ return getIntVolatile(o, offset);
+ }
+
+ /** Acquire version of {@link #getFloatVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final float getFloatAcquire(Object o, long offset) {
+ return getFloatVolatile(o, offset);
+ }
+
+ /** Acquire version of {@link #getLongVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final long getLongAcquire(Object o, long offset) {
+ return getLongVolatile(o, offset);
+ }
+
+ /** Acquire version of {@link #getDoubleVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final double getDoubleAcquire(Object o, long offset) {
+ return getDoubleVolatile(o, offset);
+ }
+
+ /** Release version of {@link #putObjectVolatile(Object, long, Object)} */
+ @HotSpotIntrinsicCandidate
+ public final void putObjectRelease(Object o, long offset, Object x) {
+ putObjectVolatile(o, offset, x);
+ }
+
+ /** Release version of {@link #putBooleanVolatile(Object, long, boolean)} */
+ @HotSpotIntrinsicCandidate
+ public final void putBooleanRelease(Object o, long offset, boolean x) {
+ putBooleanVolatile(o, offset, x);
+ }
+
+ /** Release version of {@link #putByteVolatile(Object, long, byte)} */
+ @HotSpotIntrinsicCandidate
+ public final void putByteRelease(Object o, long offset, byte x) {
+ putByteVolatile(o, offset, x);
+ }
+
+ /** Release version of {@link #putShortVolatile(Object, long, short)} */
+ @HotSpotIntrinsicCandidate
+ public final void putShortRelease(Object o, long offset, short x) {
+ putShortVolatile(o, offset, x);
+ }
+
+ /** Release version of {@link #putCharVolatile(Object, long, char)} */
+ @HotSpotIntrinsicCandidate
+ public final void putCharRelease(Object o, long offset, char x) {
+ putCharVolatile(o, offset, x);
+ }
+
+ /** Release version of {@link #putIntVolatile(Object, long, int)} */
+ @HotSpotIntrinsicCandidate
+ public final void putIntRelease(Object o, long offset, int x) {
+ putIntVolatile(o, offset, x);
+ }
+
+ /** Release version of {@link #putFloatVolatile(Object, long, float)} */
+ @HotSpotIntrinsicCandidate
+ public final void putFloatRelease(Object o, long offset, float x) {
+ putFloatVolatile(o, offset, x);
+ }
+
+ /** Release version of {@link #putLongVolatile(Object, long, long)} */
+ @HotSpotIntrinsicCandidate
+ public final void putLongRelease(Object o, long offset, long x) {
+ putLongVolatile(o, offset, x);
+ }
+
+ /** Release version of {@link #putDoubleVolatile(Object, long, double)} */
+ @HotSpotIntrinsicCandidate
+ public final void putDoubleRelease(Object o, long offset, double x) {
+ putDoubleVolatile(o, offset, x);
+ }
+
+ // ------------------------------ Opaque --------------------------------------
+
+ /** Opaque version of {@link #getObjectVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final Object getObjectOpaque(Object o, long offset) {
+ return getObjectVolatile(o, offset);
+ }
+
+ /** Opaque version of {@link #getBooleanVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final boolean getBooleanOpaque(Object o, long offset) {
+ return getBooleanVolatile(o, offset);
+ }
+
+ /** Opaque version of {@link #getByteVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final byte getByteOpaque(Object o, long offset) {
+ return getByteVolatile(o, offset);
+ }
+
+ /** Opaque version of {@link #getShortVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final short getShortOpaque(Object o, long offset) {
+ return getShortVolatile(o, offset);
+ }
+
+ /** Opaque version of {@link #getCharVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final char getCharOpaque(Object o, long offset) {
+ return getCharVolatile(o, offset);
+ }
+
+ /** Opaque version of {@link #getIntVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final int getIntOpaque(Object o, long offset) {
+ return getIntVolatile(o, offset);
+ }
+
+ /** Opaque version of {@link #getFloatVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final float getFloatOpaque(Object o, long offset) {
+ return getFloatVolatile(o, offset);
+ }
+
+ /** Opaque version of {@link #getLongVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final long getLongOpaque(Object o, long offset) {
+ return getLongVolatile(o, offset);
+ }
+
+ /** Opaque version of {@link #getDoubleVolatile(Object, long)} */
+ @HotSpotIntrinsicCandidate
+ public final double getDoubleOpaque(Object o, long offset) {
+ return getDoubleVolatile(o, offset);
+ }
+
+ /** Opaque version of {@link #putObjectVolatile(Object, long, Object)} */
+ @HotSpotIntrinsicCandidate
+ public final void putObjectOpaque(Object o, long offset, Object x) {
+ putObjectVolatile(o, offset, x);
+ }
+
+ /** Opaque version of {@link #putBooleanVolatile(Object, long, boolean)} */
+ @HotSpotIntrinsicCandidate
+ public final void putBooleanOpaque(Object o, long offset, boolean x) {
+ putBooleanVolatile(o, offset, x);
+ }
+
+ /** Opaque version of {@link #putByteVolatile(Object, long, byte)} */
+ @HotSpotIntrinsicCandidate
+ public final void putByteOpaque(Object o, long offset, byte x) {
+ putByteVolatile(o, offset, x);
+ }
+
+ /** Opaque version of {@link #putShortVolatile(Object, long, short)} */
+ @HotSpotIntrinsicCandidate
+ public final void putShortOpaque(Object o, long offset, short x) {
+ putShortVolatile(o, offset, x);
+ }
+
+ /** Opaque version of {@link #putCharVolatile(Object, long, char)} */
+ @HotSpotIntrinsicCandidate
+ public final void putCharOpaque(Object o, long offset, char x) {
+ putCharVolatile(o, offset, x);
+ }
+
+ /** Opaque version of {@link #putIntVolatile(Object, long, int)} */
+ @HotSpotIntrinsicCandidate
+ public final void putIntOpaque(Object o, long offset, int x) {
+ putIntVolatile(o, offset, x);
+ }
+
+ /** Opaque version of {@link #putFloatVolatile(Object, long, float)} */
+ @HotSpotIntrinsicCandidate
+ public final void putFloatOpaque(Object o, long offset, float x) {
+ putFloatVolatile(o, offset, x);
+ }
+
+ /** Opaque version of {@link #putLongVolatile(Object, long, long)} */
+ @HotSpotIntrinsicCandidate
+ public final void putLongOpaque(Object o, long offset, long x) {
+ putLongVolatile(o, offset, x);
+ }
+
+ /** Opaque version of {@link #putDoubleVolatile(Object, long, double)} */
+ @HotSpotIntrinsicCandidate
+ public final void putDoubleOpaque(Object o, long offset, double x) {
+ putDoubleVolatile(o, offset, x);
+ }
+
/**
* Unblocks the given thread blocked on {@code park}, or, if it is
* not blocked, causes the subsequent call to {@code park} not to
@@ -1100,6 +1438,23 @@ public final class Unsafe {
@HotSpotIntrinsicCandidate
public native void fullFence();
+ /**
+ * Ensures that loads before the fence will not be reordered with
+ * loads after the fence.
+ */
+ public final void loadLoadFence() {
+ loadFence();
+ }
+
+ /**
+ * Ensures that stores before the fence will not be reordered with
+ * stores after the fence.
+ */
+ public final void storeStoreFence() {
+ storeFence();
+ }
+
+
/**
* Throws IllegalAccessError; for use by the VM for access control
* error support.
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 057/149] 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 extends ReentrantContext> 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