From 8aa80a9245798ef7895c06a11705c651b79aa1c2 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Fri, 6 Nov 2015 14:32:34 +0100 Subject: [PATCH 001/215] 8141526: Allow to collect stdout/stderr from the FinalizationRunner even before the process returns Reviewed-by: dsamersoff --- jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java | 4 ++++ .../lib/testlibrary/jdk/testlibrary/JDKToolFinder.java | 5 +++++ .../lib/testlibrary/jdk/testlibrary/JDKToolLauncher.java | 3 +++ .../lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java | 5 +++++ .../lib/testlibrary/jdk/testlibrary/OutputBuffer.java | 5 +++++ jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java | 5 +++++ .../lib/testlibrary/jdk/testlibrary/ProcessTools.java | 8 ++++++-- .../lib/testlibrary/jdk/testlibrary/StreamPumper.java | 5 +++++ jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java | 4 ++++ 9 files changed, 42 insertions(+), 2 deletions(-) diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java b/jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java index 52b8fb0103c..594b12e3ede 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Asserts.java @@ -42,7 +42,11 @@ import java.util.Objects; * multiple times, then the line number won't provide enough context to * understand the failure. * + * + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} */ +@Deprecated public class Asserts { /** diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolFinder.java b/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolFinder.java index 69839d8e5d1..c4815229eb7 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolFinder.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolFinder.java @@ -27,6 +27,11 @@ import java.io.FileNotFoundException; import java.nio.file.Path; import java.nio.file.Paths; +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} + */ +@Deprecated public final class JDKToolFinder { private JDKToolFinder() { diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolLauncher.java b/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolLauncher.java index fcee2222b16..43f1ddb97d6 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolLauncher.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JDKToolLauncher.java @@ -46,7 +46,10 @@ import java.util.List; * Process p = pb.start(); * } * + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} */ +@Deprecated public class JDKToolLauncher { private final String executable; private final List vmArgs = new ArrayList(); diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java index 523f61c58e3..58ef07a710c 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java @@ -33,7 +33,12 @@ import java.util.regex.Pattern; /** * Utility class for verifying output and exit value from a {@code Process}. + * + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib/process} + * */ +@Deprecated public final class OutputAnalyzer { private final OutputBuffer output; private final String stdout; diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java index 5595d5cb35c..c8a5d7aab12 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java @@ -28,6 +28,11 @@ import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib/process} + */ +@Deprecated class OutputBuffer { private static class OutputBufferException extends RuntimeException { private static final long serialVersionUID = 8528687792643129571L; diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java b/jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java index c56697adb1b..2d9352c59b9 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Platform.java @@ -27,6 +27,11 @@ import java.io.RandomAccessFile; import java.io.FileNotFoundException; import java.io.IOException; +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} + */ +@Deprecated public class Platform { private static final String osName = System.getProperty("os.name"); private static final String dataModel = System.getProperty("sun.arch.data.model"); diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java index 9556f22f15f..6842de26bd4 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java @@ -27,8 +27,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -42,6 +40,12 @@ import java.util.function.Predicate; import java.util.function.Consumer; import java.util.stream.Collectors; + +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib/process} + */ +@Deprecated public final class ProcessTools { private static final class LineForwarder extends StreamPumper.LinePump { private final PrintStream ps; diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java b/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java index 7f76c6912b9..2f3c205db3c 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java @@ -34,6 +34,11 @@ import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.atomic.AtomicBoolean; +/** + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib/process} + */ +@Deprecated public final class StreamPumper implements Runnable { private static final int BUF_SIZE = 256; diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java b/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java index 780d704e1ef..c76339107c8 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/Utils.java @@ -41,7 +41,11 @@ import java.util.function.Function; /** * Common library for various test helper functions. + * + * @deprecated This class is deprecated. Use the one from + * {@code /test/lib/share/classes/jdk/test/lib} */ +@Deprecated public final class Utils { /** From 5f8e39900cd0c35d623b41bc0f35d82019809562 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Tue, 24 Nov 2015 15:40:03 +0100 Subject: [PATCH 002/215] 8143895: Fix LDFLAGS issues after JDK-8056925 Reviewed-by: ihse --- jdk/make/launcher/Launcher-jdk.accessibility.gmk | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/jdk/make/launcher/Launcher-jdk.accessibility.gmk b/jdk/make/launcher/Launcher-jdk.accessibility.gmk index 0fa486377f1..eba521c469a 100644 --- a/jdk/make/launcher/Launcher-jdk.accessibility.gmk +++ b/jdk/make/launcher/Launcher-jdk.accessibility.gmk @@ -73,8 +73,9 @@ ifeq ($(OPENJDK_TARGET_OS), windows) $$(eval $$(call SetupNativeCompilation, BUILD_JACCESSINSPECTOR$1, \ SRC := $(TOPDIR)/jaccessinspector $(TOPDIR)/common \ $(TOPDIR)/toolscommon $(TOPDIR)/include/bridge, \ - CFLAGS := $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 /EHsc, \ - LDFLAGS := $$(LDFLAGS_JDKEXE) /STACK:655360 Advapi32.lib User32.lib, \ + CFLAGS := $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 -EHsc, \ + LDFLAGS := $$(LDFLAGS_JDKEXE) -stack:655360, \ + LIBS := advapi32.lib user32.lib, \ OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/jdk.accessibility/jaccessinspector$1, \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/jdk.accessibility, \ PROGRAM := jaccessinspector$1, \ @@ -100,8 +101,9 @@ ifeq ($(OPENJDK_TARGET_OS), windows) $$(eval $$(call SetupNativeCompilation,BUILD_JACCESSWALKER$1, \ SRC := $(TOPDIR)/jaccesswalker $(TOPDIR)/common \ $(TOPDIR)/toolscommon $(TOPDIR)/include/bridge, \ - CFLAGS :== $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 /EHsc, \ - LDFLAGS := $$(LDFLAGS_JDKEXE) /STACK:655360 Advapi32.lib Comctl32.lib Gdi32.lib User32.lib, \ + CFLAGS := $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 -EHsc, \ + LDFLAGS := $$(LDFLAGS_JDKEXE) -stack:655360, \ + LIBS := advapi32.lib comctl32.lib gdi32.lib user32.lib, \ OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/jdk.accessibility/jaccesswalker$1, \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/jdk.accessibility, \ PROGRAM := jaccesswalker$1, \ From 3c1af171595aaf96cc34750bd5e54433d55ffd9e Mon Sep 17 00:00:00 2001 From: Steven Loomis Date: Tue, 24 Nov 2015 13:36:12 -0800 Subject: [PATCH 003/215] 8068619: remove unused internal function in layout No functional change. Removes unused code. Makes JDK's layout engine have the same signature as ICU HarfBuzz's wrapper. Reviewed: http://mail.openjdk.java.net/pipermail/2d-dev/2015-March/005156.html Reviewed-by: prr --- .../libfontmanager/FontInstanceAdapter.cpp | 6 ----- .../libfontmanager/FontInstanceAdapter.h | 1 - .../libfontmanager/layout/LEFontInstance.h | 24 +------------------ 3 files changed, 1 insertion(+), 30 deletions(-) diff --git a/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.cpp b/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.cpp index 8c8c47593fb..3d133952d4d 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.cpp +++ b/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.cpp @@ -67,12 +67,6 @@ FontInstanceAdapter::FontInstanceAdapter(JNIEnv *theEnv, }; -const void *FontInstanceAdapter::getFontTable(LETag tableTag) const -{ - size_t ignored = 0; - return getFontTable(tableTag, ignored); -} - static const LETag cacheMap[LAYOUTCACHE_ENTRIES] = { GPOS_TAG, GDEF_TAG, GSUB_TAG, MORT_TAG, MORX_TAG, KERN_TAG }; diff --git a/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.h b/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.h index 8d2ee3073a0..0d8322dddbe 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.h +++ b/jdk/src/java.desktop/share/native/libfontmanager/FontInstanceAdapter.h @@ -85,7 +85,6 @@ public: // tables are cached with the native font scaler data // only supports gsub, gpos, gdef, mort tables at present - virtual const void *getFontTable(LETag tableTag) const; virtual const void *getFontTable(LETag tableTag, size_t &len) const; virtual void *getKernPairs() const { diff --git a/jdk/src/java.desktop/share/native/libfontmanager/layout/LEFontInstance.h b/jdk/src/java.desktop/share/native/libfontmanager/layout/LEFontInstance.h index 2baf2d6c85e..3ac687906fa 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/layout/LEFontInstance.h +++ b/jdk/src/java.desktop/share/native/libfontmanager/layout/LEFontInstance.h @@ -172,28 +172,6 @@ public: // Font file access // - /** - * This method reads a table from the font. Note that in general, - * it only makes sense to call this method on an LEFontInstance - * which represents a physical font - i.e. one which has been returned by - * getSubFont(). This is because each subfont in a composite font - * will have different tables, and there's no way to know which subfont to access. - * - * Subclasses which represent composite fonts should always return NULL. - * - * Note that implementing this function does not allow for range checking. - * Subclasses that desire the safety of range checking must implement the - * variation which has a length parameter. - * - * @param tableTag - the four byte table tag. (e.g. 'cmap') - * - * @return the address of the table in memory, or NULL - * if the table doesn't exist. - * - * @stable ICU 2.8 - */ - virtual const void *getFontTable(LETag tableTag) const = 0; - /** * This method reads a table from the font. Note that in general, * it only makes sense to call this method on an LEFontInstance @@ -213,7 +191,7 @@ public: * if the table doesn't exist. * @internal */ - virtual const void* getFontTable(LETag tableTag, size_t &length) const { length=-1; return getFontTable(tableTag); } /* -1 = unknown length */ + virtual const void* getFontTable(LETag tableTag, size_t &length) const = 0; virtual void *getKernPairs() const = 0; virtual void setKernPairs(void *pairs) const = 0; From 69b04049b56d38ae5811850c9d44a997fa6bd1d1 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 25 Nov 2015 14:44:29 +0300 Subject: [PATCH 004/215] 7063986: Wrong JNi method call in font scaler Reviewed-by: prr, rchamyal --- .../java.desktop/share/native/libfontmanager/freetypeScaler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c b/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c index 5fe5372be2f..c2a294f91b7 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c +++ b/jdk/src/java.desktop/share/native/libfontmanager/freetypeScaler.c @@ -258,7 +258,7 @@ Java_sun_font_FreetypeFontScaler_initNativeScaler( scalerInfo->fontData, scalerInfo->fontDataLength); if (bBuffer != NULL) { - (*env)->CallObjectMethod(env, font2D, + (*env)->CallVoidMethod(env, font2D, sunFontIDs.readFileMID, bBuffer); error = FT_New_Memory_Face(scalerInfo->library, From bcb678575580e78beb157c5706c10b4ea521250a Mon Sep 17 00:00:00 2001 From: Ambarish Rapte Date: Thu, 26 Nov 2015 19:12:28 +0400 Subject: [PATCH 005/215] 8055197: TextField deletes multiline strings Reviewed-by: serb, alexsch --- .../share/classes/java/awt/TextField.java | 21 +- .../java/awt/TextField/EOLTest/EOLTest.java | 202 ++++++++++++++++++ 2 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 jdk/test/java/awt/TextField/EOLTest/EOLTest.java diff --git a/jdk/src/java.desktop/share/classes/java/awt/TextField.java b/jdk/src/java.desktop/share/classes/java/awt/TextField.java index de6b5cda6d4..2dfd19c4128 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/TextField.java +++ b/jdk/src/java.desktop/share/classes/java/awt/TextField.java @@ -198,7 +198,7 @@ public class TextField extends TextComponent { * @see java.awt.GraphicsEnvironment#isHeadless */ public TextField(String text, int columns) throws HeadlessException { - super(text); + super(replaceEOL(text)); this.columns = (columns >= 0) ? columns : 0; } @@ -297,12 +297,28 @@ public class TextField extends TextComponent { * @see java.awt.TextComponent#getText */ public void setText(String t) { - super.setText(t); + super.setText(replaceEOL(t)); // This could change the preferred size of the Component. invalidateIfValid(); } + /** + * Replaces EOL characters from the text variable with a space character. + * @param text the new text. + * @return Returns text after replacing EOL characters. + */ + private static String replaceEOL(String text) { + String[] strEOLs = {System.lineSeparator(), "\n"}; + for (String eol : strEOLs) { + if (text.contains(eol)) { + text = text.replace(eol, " "); + } + } + return text; + } + + /** * Indicates whether or not this text field has a * character set for echoing. @@ -704,6 +720,7 @@ public class TextField extends TextComponent { { // HeadlessException will be thrown by TextComponent's readObject s.defaultReadObject(); + text = replaceEOL(text); // Make sure the state we just read in for columns has legal values if (columns < 0) { diff --git a/jdk/test/java/awt/TextField/EOLTest/EOLTest.java b/jdk/test/java/awt/TextField/EOLTest/EOLTest.java new file mode 100644 index 00000000000..a9ab7b0941d --- /dev/null +++ b/jdk/test/java/awt/TextField/EOLTest/EOLTest.java @@ -0,0 +1,202 @@ +/* + * 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 8055197 7186036 + @summary TextField should replace EOL character with space character + @run main EOLTest + */ + +import java.awt.Frame; +import java.awt.TextField; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInput; +import java.io.ObjectInputStream; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; + +public class EOLTest { + + private Frame mainFrame; + private TextField textField; + private String testStrEOL; + private boolean isTestFail; + private int testFailCount; + StringBuilder testFailMessage; + private String expectedString = "Row1 Row2 Row3"; + + public EOLTest() { + mainFrame = new Frame(); + mainFrame.setSize(200, 200); + mainFrame.setVisible(true); + testFailMessage = new StringBuilder(); + testStrEOL = "Row1" + System.lineSeparator() + "Row2\nRow3"; + } + + private void testConstructor1() { + textField = new TextField(testStrEOL); + textField.setSize(200, 100); + mainFrame.add(textField); + checkTest(); + mainFrame.remove(textField); + } + + private void testConstructor2() { + textField = new TextField(30); + textField.setSize(200, 100); + mainFrame.add(textField); + textField.setText(testStrEOL); + checkTest(); + mainFrame.remove(textField); + } + + private void testConstructor3() { + textField = new TextField(testStrEOL, 30); + textField.setSize(200, 100); + mainFrame.add(textField); + checkTest(); + mainFrame.remove(textField); + } + + private void testSetText() { + textField = new TextField(); + textField.setSize(200, 100); + textField.setText(testStrEOL); + mainFrame.add(textField); + checkTest(); + mainFrame.remove(textField); + } + + private void testDeserialization() { + TextField textFieldToSerialize = new TextField(testStrEOL); + textFieldToSerialize.setSize(200, 100); + mainFrame.add(textFieldToSerialize); + try { + // Serialize TextField object "textFieldToSerialize". + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutput outStream = new ObjectOutputStream(baos); + outStream.writeObject(textFieldToSerialize); + + // Search the text variable data through serialized object stream. + byte[] streamedBytes = baos.toByteArray(); + int foundLoc = 0; + for (int i = 0; i < streamedBytes.length; ++i) { + if (streamedBytes[i] == expectedString.charAt(0)) { + foundLoc = i; + int j = 1; + for (; j < expectedString.length(); ++j) { + if (streamedBytes[i+j] != expectedString.charAt(j)) { + break; + } + } + if (j == expectedString.length()) { + break; + } + } + foundLoc = -1; + } + + if (foundLoc == -1) { + // Could not find text data in serialized object stream. + throw new Exception("Could not find text data in serialized " + + "object stream."); + } + // Replace space character from serialized stream with + // EOL character for testing de-serialization. + String EOLChar = System.lineSeparator(); + String newExpectedString = ""; + for (int i = foundLoc, j = 0; j < expectedString.length(); ++i, ++j) { + newExpectedString += (char)(streamedBytes[i]); + if (streamedBytes[i] == ' ') { + int k = 0; + for (; k < EOLChar.length(); ++k) { + streamedBytes[i + k] = (byte) EOLChar.charAt(k); + } + i += k-1; + j += k-1; + } + } + // New line character varies with platform, + // ex. For windows '\r\n', for linux '\n'. + // While replacing space from serialized object stream, the length + // of EOL character will affect the expected string as well. + expectedString = newExpectedString; + + // De-serialize TextField object stream. + ByteArrayInputStream bais = new ByteArrayInputStream(streamedBytes); + ObjectInput inStream = new ObjectInputStream(bais); + textField = (TextField) inStream.readObject(); + } catch (Exception ex) { + // Serialization or De-serialization failed. + // Create textField with empty string to show failure. + ex.printStackTrace(); + textField = new TextField(); + } + + checkTest(); + mainFrame.remove(textFieldToSerialize); + } + + private void checkTest() { + if (!textField.getText().equals(expectedString)) { + testFailMessage.append("TestFail line : "); + testFailMessage.append(Thread.currentThread().getStackTrace()[2]. + getLineNumber()); + testFailMessage.append(" TextField.getText() : \""); + testFailMessage.append(textField.getText()); + testFailMessage.append("\" does not match expected string : \""); + testFailMessage.append(expectedString).append("\""); + testFailMessage.append(System.getProperty("line.separator")); + testFailCount++; + isTestFail = true; + } + } + + private void checkFailures() { + if (isTestFail) { + testFailMessage.insert(0, "Test Fail count : " + testFailCount + + System.getProperty("line.separator")); + dispose(); + throw new RuntimeException(testFailMessage.toString()); + } + } + + private void dispose() { + if (mainFrame != null) { + mainFrame.dispose(); + } + } + + public static void main(String[] args) { + EOLTest testEOL = new EOLTest(); + testEOL.testConstructor1(); + testEOL.testConstructor2(); + testEOL.testConstructor3(); + testEOL.testSetText(); + testEOL.testDeserialization(); + testEOL.checkFailures(); + testEOL.dispose(); + } +} \ No newline at end of file From b97ff269d0cc7c79a82f6b319f0fe6f020fbe4e2 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 1 Dec 2015 12:17:18 +0100 Subject: [PATCH 006/215] 8143930: C1 LinearScan asserts when compiling two back-to-back CompareAndSwapLongs Refactor CAS code to decrease register pressure in c1 Reviewed-by: kvn, shade --- .../src/cpu/x86/vm/c1_LIRGenerator_x86.cpp | 26 +++---- .../intrinsics/unsafe/UnsafeTwoCASLong.java | 77 +++++++++++++++++++ 2 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 hotspot/test/compiler/intrinsics/unsafe/UnsafeTwoCASLong.java diff --git a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp index 8303fe989c8..e7ba64b69e6 100644 --- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp @@ -736,19 +736,6 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { obj.load_item(); offset.load_nonconstant(); - if (type == objectType) { - cmp.load_item_force(FrameMap::rax_oop_opr); - val.load_item(); - } else if (type == intType) { - cmp.load_item_force(FrameMap::rax_opr); - val.load_item(); - } else if (type == longType) { - cmp.load_item_force(FrameMap::long0_opr); - val.load_item_force(FrameMap::long1_opr); - } else { - ShouldNotReachHere(); - } - LIR_Opr addr = new_pointer_register(); LIR_Address* a; if(offset.result()->is_constant()) { @@ -785,6 +772,19 @@ void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { true /* do_load */, false /* patch */, NULL); } + if (type == objectType) { + cmp.load_item_force(FrameMap::rax_oop_opr); + val.load_item(); + } else if (type == intType) { + cmp.load_item_force(FrameMap::rax_opr); + val.load_item(); + } else if (type == longType) { + cmp.load_item_force(FrameMap::long0_opr); + val.load_item_force(FrameMap::long1_opr); + } else { + ShouldNotReachHere(); + } + LIR_Opr ill = LIR_OprFact::illegalOpr; // for convenience if (type == objectType) __ cas_obj(addr, cmp.result(), val.result(), ill, ill); diff --git a/hotspot/test/compiler/intrinsics/unsafe/UnsafeTwoCASLong.java b/hotspot/test/compiler/intrinsics/unsafe/UnsafeTwoCASLong.java new file mode 100644 index 00000000000..224d22ca42c --- /dev/null +++ b/hotspot/test/compiler/intrinsics/unsafe/UnsafeTwoCASLong.java @@ -0,0 +1,77 @@ +/* + * 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 8143930 + * @summary C1 LinearScan asserts when compiling two back-to-back CompareAndSwapLongs + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=200000 -XX:TieredStopAtLevel=1 UnsafeTwoCASLong + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class UnsafeTwoCASLong { + static final int ITERS = Integer.getInteger("iters", 1); + static final jdk.internal.misc.Unsafe UNSAFE; + static final long V_OFFSET; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field vField = UnsafeTwoCASLong.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + long v; + + @Test + public void testFieldInstance() { + UnsafeTwoCASLong t = new UnsafeTwoCASLong(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + static void testAccess(Object base, long offset) { + UNSAFE.compareAndSwapLong(base, offset, 1L, 2L); + UNSAFE.compareAndSwapLong(base, offset, 2L, 1L); + } + +} + From 39ce42b41e470034869b79d8ab1fdcde1456477b Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 1 Dec 2015 19:02:50 +0300 Subject: [PATCH 007/215] 8081457: TrayIcon tests fail in OEL 7 only Reviewed-by: alexsch, serb, azvegint --- .../classes/sun/awt/X11/XTrayIconPeer.java | 1 + .../TrayIcon/ActionCommand/ActionCommand.java | 7 +- .../ActionEventMask/ActionEventMask.java | 6 +- .../TrayIcon/ModalityTest/ModalityTest.java | 66 ++++++++++++------ .../MouseEventMask/MouseEventMaskTest.java | 4 +- .../MouseMovedTest/MouseMovedTest.java | 12 +++- .../FunctionalityCheck.java | 69 ++++++++++++------- .../FunctionalityCheck/tray.policy | 2 + .../awt/TrayIcon/SystemTrayIconHelper.java | 42 ++++++++++- .../TrayIconEventModifiersTest.java | 8 ++- .../TrayIconEvents/TrayIconEventsTest.java | 67 ++++++++++++------ .../TrayIconMouseTest/TrayIconMouseTest.java | 10 ++- .../TrayIconPopup/TrayIconPopupTest.java | 4 +- 13 files changed, 217 insertions(+), 81 deletions(-) diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java index eba30a7e2af..20b7a9d7899 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XTrayIconPeer.java @@ -413,6 +413,7 @@ public class XTrayIconPeer implements TrayIconPeer, void addListeners() { canvas.addMouseListener(eventProxy); canvas.addMouseMotionListener(eventProxy); + eframe.addMouseListener(eventProxy); } long getWindow() { diff --git a/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java b/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java index 5c5a17e0dbc..ce5495e3585 100644 --- a/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java +++ b/jdk/test/java/awt/TrayIcon/ActionCommand/ActionCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -59,8 +59,11 @@ public class ActionCommand { "and rerun test."); } else if (System.getProperty("os.name").toLowerCase().startsWith("mac")){ isMacOS = true; + } else if (SystemTrayIconHelper.isOel7()) { + System.out.println("OEL 7 doesn't support double click in " + + "systray. Skipped"); + return; } - new ActionCommand().doTest(); } } diff --git a/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java b/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java index fb95874eadc..ebafe40e282 100644 --- a/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java +++ b/jdk/test/java/awt/TrayIcon/ActionEventMask/ActionEventMask.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -66,6 +66,10 @@ public class ActionEventMask { } else { if (System.getProperty("os.name").toLowerCase().startsWith("mac")) { isMacOS = true; + } else if (SystemTrayIconHelper.isOel7()) { + System.out.println("OEL 7 doesn't support double click in " + + "systray. Skipped"); + return; } new ActionEventMask().doTest(); } diff --git a/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java b/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java index 2118457ee79..4c0bb1d3c4a 100644 --- a/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java +++ b/jdk/test/java/awt/TrayIcon/ModalityTest/ModalityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -35,6 +35,7 @@ import java.awt.image.BufferedImage; */ public class ModalityTest { + private static boolean isOEL7; TrayIcon icon; ExtendedRobot robot; Dialog d; @@ -80,7 +81,7 @@ public class ModalityTest { "\"Always show all icons and notifications on the taskbar\" true " + "to avoid this problem. Or change behavior only for Java SE tray " + "icon and rerun test."); - + isOEL7 = SystemTrayIconHelper.isOel7(); new ModalityTest().doTest(); } } @@ -225,6 +226,12 @@ public class ModalityTest { Point iconPosition = SystemTrayIconHelper.getTrayIconLocation(icon); if (iconPosition == null) throw new RuntimeException("Unable to find the icon location!"); + if (isOEL7) { + // close tray + robot.mouseMove(100,100); + robot.click(InputEvent.BUTTON1_MASK); + robot.waitForIdle(2000); + } if (! d.isVisible()) throw new RuntimeException("FAIL: The modal dialog is not yet visible"); @@ -232,27 +239,35 @@ public class ModalityTest { robot.mouseMove(iconPosition.x, iconPosition.y); robot.waitForIdle(2000); - SystemTrayIconHelper.doubleClick(robot); + if(!isOEL7) { + SystemTrayIconHelper.doubleClick(robot); - if (! actionPerformed) { - synchronized (actionLock) { - try { - actionLock.wait(3000); - } catch (Exception e) { + if (!actionPerformed) { + synchronized (actionLock) { + try { + actionLock.wait(3000); + } catch (Exception e) { + } } } + if (!actionPerformed) + throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked"); } - if (! actionPerformed) - throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked"); for (int i = 0; i < buttonTypes.length; i++) { mousePressed = false; - robot.mousePress(buttonTypes[i]); + if(isOEL7) { + SystemTrayIconHelper.openTrayIfNeeded(robot); + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.click(buttonTypes[i]); + } else { + robot.mousePress(buttonTypes[i]); + } if (! mousePressed) { synchronized (pressLock) { try { - pressLock.wait(3000); + pressLock.wait(6000); } catch (Exception e) { } } @@ -264,12 +279,18 @@ public class ModalityTest { mouseReleased = false; mouseClicked = false; - robot.mouseRelease(buttonTypes[i]); + if(isOEL7) { + SystemTrayIconHelper.openTrayIfNeeded(robot); + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.click(buttonTypes[i]); + } else { + robot.mouseRelease(buttonTypes[i]); + } if (! mouseReleased) { synchronized (releaseLock) { try { - releaseLock.wait(3000); + releaseLock.wait(6000); } catch (Exception e) { } } @@ -281,7 +302,7 @@ public class ModalityTest { if (! mouseClicked) { synchronized (clickLock) { try { - clickLock.wait(3000); + clickLock.wait(6000); } catch (Exception e) { } } @@ -290,13 +311,14 @@ public class ModalityTest { throw new RuntimeException("FAIL: mouseClicked not triggered when " + buttonNames[i] + " pressed & released"); } + if (!isOEL7) { + mouseMoved = false; + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.glide(iconPosition.x + 100, iconPosition.y); - mouseMoved = false; - robot.mouseMove(iconPosition.x, iconPosition.y); - robot.glide(iconPosition.x + 100, iconPosition.y); - - if (! mouseMoved) - if (! SystemTrayIconHelper.skip(0) ) - throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon"); + if (!mouseMoved) + if (!SystemTrayIconHelper.skip(0)) + throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon"); + } } } diff --git a/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java b/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java index e6c194ec69c..113ec7e9d71 100644 --- a/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java +++ b/jdk/test/java/awt/TrayIcon/MouseEventMask/MouseEventMaskTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -71,6 +71,8 @@ public class MouseEventMaskTest { "\"Always show all icons and notifications on the taskbar\" true " + "to avoid this problem. Or change behavior only for Java SE tray " + "icon and rerun test."); + } else if (SystemTrayIconHelper.isOel7()) { + return; } new MouseEventMaskTest().doTest(); } diff --git a/jdk/test/java/awt/TrayIcon/MouseMovedTest/MouseMovedTest.java b/jdk/test/java/awt/TrayIcon/MouseMovedTest/MouseMovedTest.java index 04d91f23859..d6e6d760f79 100644 --- a/jdk/test/java/awt/TrayIcon/MouseMovedTest/MouseMovedTest.java +++ b/jdk/test/java/awt/TrayIcon/MouseMovedTest/MouseMovedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -31,7 +31,7 @@ import java.awt.image.BufferedImage; * @summary Check for mouseMoved event for java.awt.TrayIcon * @author Dmitriy Ermashov (dmitriy.ermashov@oracle.com) * @library ../../../../lib/testlibrary - * @build ExtendedRobot + * @build ExtendedRobot SystemTrayIconHelper * @run main MouseMovedTest */ @@ -39,6 +39,14 @@ public class MouseMovedTest { static volatile boolean moved; public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + return; + } + + if (SystemTrayIconHelper.isOel7()) { + return; + } + moved = false; TrayIcon icon = new TrayIcon(new BufferedImage(20, 20, BufferedImage.TYPE_INT_RGB), "Test icon"); diff --git a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java index 5918ac3dfc0..c9d2eade8c3 100644 --- a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java +++ b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/FunctionalityCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -51,6 +51,7 @@ public class FunctionalityCheck { boolean mouseReleased = false; boolean mouseClicked = false; boolean mouseMoved = false; + static boolean isOEL7; static final int[] buttonTypes = { InputEvent.BUTTON1_MASK, @@ -69,6 +70,7 @@ public class FunctionalityCheck { System.out.println("SystemTray not supported on the platform under test. " + "Marking the test passed"); } else { + isOEL7 = SystemTrayIconHelper.isOel7(); new FunctionalityCheck().doTest(); } } @@ -188,31 +190,44 @@ public class FunctionalityCheck { Point iconPosition = SystemTrayIconHelper.getTrayIconLocation(icon); if (iconPosition == null) throw new RuntimeException("Unable to find the icon location!"); + if (isOEL7) { + // close tray + robot.mouseMove(100,100); + robot.click(InputEvent.BUTTON1_MASK); + robot.waitForIdle(2000); + } robot.mouseMove(iconPosition.x, iconPosition.y); - robot.waitForIdle(2000); + robot.waitForIdle(); + if(!isOEL7) { + SystemTrayIconHelper.doubleClick(robot); - SystemTrayIconHelper.doubleClick(robot); - - if (! actionPerformed) { - synchronized (actionLock) { - try { - actionLock.wait(3000); - } catch (Exception e) { + if (!actionPerformed) { + synchronized (actionLock) { + try { + actionLock.wait(3000); + } catch (Exception e) { + } } } + if (!actionPerformed) + throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked"); } - if (! actionPerformed) - throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked"); for (int i = 0; i < buttonTypes.length; i++) { mousePressed = false; - robot.mousePress(buttonTypes[i]); + if(isOEL7) { + SystemTrayIconHelper.openTrayIfNeeded(robot); + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.click(buttonTypes[i]); + } else { + robot.mousePress(buttonTypes[i]); + } if (! mousePressed) { synchronized (pressLock) { try { - pressLock.wait(3000); + pressLock.wait(6000); } catch (Exception e) { } } @@ -224,12 +239,17 @@ public class FunctionalityCheck { mouseReleased = false; mouseClicked = false; - robot.mouseRelease(buttonTypes[i]); - + if(isOEL7) { + SystemTrayIconHelper.openTrayIfNeeded(robot); + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.click(buttonTypes[i]); + } else { + robot.mouseRelease(buttonTypes[i]); + } if (! mouseReleased) { synchronized (releaseLock) { try { - releaseLock.wait(3000); + releaseLock.wait(6000); } catch (Exception e) { } } @@ -242,7 +262,7 @@ public class FunctionalityCheck { if (! mouseClicked) { synchronized (clickLock) { try { - clickLock.wait(3000); + clickLock.wait(6000); } catch (Exception e) { } } @@ -251,13 +271,14 @@ public class FunctionalityCheck { throw new RuntimeException("FAIL: mouseClicked not triggered when " + buttonNames[i] + " pressed & released"); } + if(!isOEL7) { + mouseMoved = false; + robot.mouseMove(iconPosition.x + 100, iconPosition.y); + robot.glide(iconPosition.x, iconPosition.y); - mouseMoved = false; - robot.mouseMove(iconPosition.x + 100, iconPosition.y); - robot.glide(iconPosition.x, iconPosition.y); - - if (! mouseMoved) - if (! SystemTrayIconHelper.skip(0) ) - throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon"); + if (!mouseMoved) + if (!SystemTrayIconHelper.skip(0)) + throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon"); + } } } diff --git a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/tray.policy b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/tray.policy index 845bfb8d80b..c2c76434cd3 100644 --- a/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/tray.policy +++ b/jdk/test/java/awt/TrayIcon/SecurityCheck/FunctionalityCheck/tray.policy @@ -5,6 +5,7 @@ grant { permission java.util.PropertyPermission "resultsDir", "read"; permission java.util.PropertyPermission "user.home", "read"; permission java.util.PropertyPermission "os.name", "read"; + permission java.util.PropertyPermission "os.version", "read"; permission java.awt.AWTPermission "accessEventQueue"; permission java.lang.RuntimePermission "setIO"; permission java.lang.RuntimePermission "accessDeclaredMembers"; @@ -17,5 +18,6 @@ grant { permission java.util.PropertyPermission "java.class.path", "read"; permission java.awt.AWTPermission "readDisplayPixels"; permission java.awt.AWTPermission "watchMousePointer"; + }; diff --git a/jdk/test/java/awt/TrayIcon/SystemTrayIconHelper.java b/jdk/test/java/awt/TrayIcon/SystemTrayIconHelper.java index a8f6e2f7cf5..cb36b8fdba3 100644 --- a/jdk/test/java/awt/TrayIcon/SystemTrayIconHelper.java +++ b/jdk/test/java/awt/TrayIcon/SystemTrayIconHelper.java @@ -66,7 +66,9 @@ public class SystemTrayIconHelper { for (int x = (int) (screenSize.getWidth()-width); x > 0; x--) { for (int y = (int) (screenSize.getHeight()-height); y > (screenSize.getHeight()-50); y--) { if (imagesEquals(((BufferedImage)icon.getImage()).getSubimage(0, 0, width, height), screen.getSubimage(x, y, width, height))) { - return new Point(x+5, y+5); + Point point = new Point(x + 5, y + 5); + System.out.println("Icon location " + point); + return point; } } } @@ -91,6 +93,7 @@ public class SystemTrayIconHelper { point2d = (Point2D)m_getLocation.invoke(peer, new Object[]{model}); Point po = new Point((int)(point2d.getX()), (int)(point2d.getY())); po.translate(10, -5); + System.out.println("Icon location " + po); return po; }catch(Exception e) { e.printStackTrace(); @@ -101,12 +104,15 @@ public class SystemTrayIconHelper { // sun.awt.X11.XTrayIconPeer Field f_peer = getField(java.awt.TrayIcon.class, "peer"); + SystemTrayIconHelper.openTrayIfNeeded(robot); + Object peer = f_peer.get(icon); Method m_getLOS = peer.getClass().getDeclaredMethod( "getLocationOnScreen", new Class[]{}); m_getLOS.setAccessible(true); Point point = (Point)m_getLOS.invoke(peer, new Object[]{}); point.translate(5, 5); + System.out.println("Icon location " + point); return point; } catch (Exception e) { e.printStackTrace(); @@ -169,4 +175,38 @@ public class SystemTrayIconHelper { } return false; } + + public static boolean openTrayIfNeeded(Robot robot) { + String sysv = System.getProperty("os.version"); + System.out.println("System version is " + sysv); + //Additional step to raise the system try in Gnome 3 in OEL 7 + if(isOel7()) { + System.out.println("OEL 7 detected"); + GraphicsConfiguration gc = GraphicsEnvironment. + getLocalGraphicsEnvironment().getDefaultScreenDevice(). + getDefaultConfiguration(); + Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc); + if(insets.bottom > 0) { + Dimension screenSize = Toolkit.getDefaultToolkit() + .getScreenSize(); + robot.mouseMove(screenSize.width - insets.bottom / 2, + screenSize.height - insets.bottom / 2); + robot.delay(50); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.delay(50); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.waitForIdle(); + robot.delay(1000); + System.out.println("Tray is opened"); + return true; + } + } + return false; + } + + public static boolean isOel7() { + return System.getProperty("os.name").toLowerCase() + .contains("linux") && System.getProperty("os.version") + .toLowerCase().contains("el7"); + } } diff --git a/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java b/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java index 9cdce634a92..b80db75b510 100644 --- a/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java +++ b/jdk/test/java/awt/TrayIcon/TrayIconEventModifiers/TrayIconEventModifiersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -121,6 +121,12 @@ public class TrayIconEventModifiersTest { }; } + if (SystemTrayIconHelper.isOel7()) { + System.out.println("OEL 7 doesn't support click modifiers in " + + "systray. Skipped"); + return; + } + new TrayIconEventModifiersTest().doTest(); } } diff --git a/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java b/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java index c7c79ea6570..275e51065ca 100644 --- a/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java +++ b/jdk/test/java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -37,6 +37,7 @@ import java.awt.image.BufferedImage; public class TrayIconEventsTest { + private static boolean isOEL7; TrayIcon icon; ExtendedRobot robot; @@ -77,6 +78,7 @@ public class TrayIconEventsTest { "\"Always show all icons and notifications on the taskbar\" true " + "to avoid this problem. Or change behavior only for Java SE " + "tray icon."); + isOEL7 = SystemTrayIconHelper.isOel7(); new TrayIconEventsTest().doTest(); } } @@ -195,31 +197,44 @@ public class TrayIconEventsTest { Point iconPosition = SystemTrayIconHelper.getTrayIconLocation(icon); if (iconPosition == null) throw new RuntimeException("Unable to find the icon location!"); + if (isOEL7) { + // close tray + robot.mouseMove(100,100); + robot.click(InputEvent.BUTTON1_MASK); + robot.waitForIdle(2000); + } robot.mouseMove(iconPosition.x, iconPosition.y); - robot.waitForIdle(2000); + robot.waitForIdle(); + if(!isOEL7) { + SystemTrayIconHelper.doubleClick(robot); - SystemTrayIconHelper.doubleClick(robot); - - if (! actionPerformed) { - synchronized (actionLock) { - try { - actionLock.wait(10000); - } catch (Exception e) { + if (!actionPerformed) { + synchronized (actionLock) { + try { + actionLock.wait(10000); + } catch (Exception e) { + } } } + if (!actionPerformed) + throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked"); } - if (! actionPerformed) - throw new RuntimeException("FAIL: ActionEvent not triggered when TrayIcon is double clicked"); for (int i = 0; i < buttonTypes.length; i++) { mousePressed = false; - robot.mousePress(buttonTypes[i]); + if(isOEL7) { + SystemTrayIconHelper.openTrayIfNeeded(robot); + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.click(buttonTypes[i]); + } else { + robot.mousePress(buttonTypes[i]); + } if (! mousePressed) { synchronized (pressLock) { try { - pressLock.wait(3000); + pressLock.wait(6000); } catch (Exception e) { } } @@ -231,12 +246,18 @@ public class TrayIconEventsTest { mouseReleased = false; mouseClicked = false; - robot.mouseRelease(buttonTypes[i]); + if(isOEL7) { + SystemTrayIconHelper.openTrayIfNeeded(robot); + robot.mouseMove(iconPosition.x, iconPosition.y); + robot.click(buttonTypes[i]); + } else { + robot.mouseRelease(buttonTypes[i]); + } if (! mouseReleased) { synchronized (releaseLock) { try { - releaseLock.wait(3000); + releaseLock.wait(6000); } catch (Exception e) { } } @@ -248,7 +269,7 @@ public class TrayIconEventsTest { if (! mouseClicked) { synchronized (clickLock) { try { - clickLock.wait(3000); + clickLock.wait(6000); } catch (Exception e) { } } @@ -258,12 +279,14 @@ public class TrayIconEventsTest { buttonNames[i] + " pressed & released"); } - mouseMoved = false; - robot.mouseMove(iconPosition.x + 100, iconPosition.y); - robot.glide(iconPosition.x, iconPosition.y); + if (!isOEL7) { + mouseMoved = false; + robot.mouseMove(iconPosition.x + 100, iconPosition.y); + robot.glide(iconPosition.x, iconPosition.y); - if (! mouseMoved) - if (! SystemTrayIconHelper.skip(0) ) - throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon"); + if (!mouseMoved) + if (!SystemTrayIconHelper.skip(0)) + throw new RuntimeException("FAIL: mouseMoved not triggered even when mouse moved over the icon"); + } } } diff --git a/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java b/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java index 124ceba5399..b8f6a69d30c 100644 --- a/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java +++ b/jdk/test/java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -66,6 +66,10 @@ public class TrayIconMouseTest { } else { if (System.getProperty("os.name").toLowerCase().startsWith("mac")) { isMacOS = true; + } else if (SystemTrayIconHelper.isOel7()) { + System.out.println("OEL 7 doesn't support double click in " + + "systray. Skipped"); + return; } new TrayIconMouseTest().doTest(); } @@ -108,7 +112,7 @@ public class TrayIconMouseTest { for (int i = 0; i < buttonTypes.length; i++) { actionPerformed = false; robot.click(buttonTypes[i]); - robot.waitForIdle(2000); + robot.waitForIdle(6000); if (isMacOS && actionPerformed && i == 2) { @@ -155,7 +159,7 @@ public class TrayIconMouseTest { if (! actionPerformed) { synchronized (actionLock) { try { - actionLock.wait(3000); + actionLock.wait(6000); } catch (Exception e) { } } diff --git a/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java b/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java index f866cc18aa0..a81e516bd0e 100644 --- a/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java +++ b/jdk/test/java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -127,7 +127,7 @@ public class TrayIconPopupTest { robot.mousePress(InputEvent.BUTTON3_MASK); robot.delay(50); robot.mouseRelease(InputEvent.BUTTON3_MASK); - robot.delay(1000); + robot.delay(6000); robot.mouseMove(window.getLocation().x + 10, window.getLocation().y + 10); robot.mousePress(InputEvent.BUTTON3_MASK); From afabb1b2c0e38ad2f124489faab54456d85b9c96 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 1 Dec 2015 19:07:45 +0300 Subject: [PATCH 008/215] 8068228: Test closed/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest fails with GTKLookAndFeel Reviewed-by: ssadetsky, arapte --- .../MaximizedFrameTest.html | 42 ---- .../MaximizedFrameTest.java | 200 +++++++++++------- 2 files changed, 129 insertions(+), 113 deletions(-) delete mode 100644 jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html diff --git a/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html b/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html deleted file mode 100644 index 97781dc7643..00000000000 --- a/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2008, 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. - */ - - - - - - - -

bug 6176814
Bug ID: 6176814

- -

This is an AUTOMATIC test, simply wait for completion

- - - - diff --git a/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.java b/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.java index c2ee806bb19..e519d3dad19 100644 --- a/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.java +++ b/jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -22,91 +22,149 @@ */ /* - test - @bug 6176814 - @summary Metalworks frame maximizes after the move - @author Andrei.Dmitriev area=Event - @run applet MaximizedFrameTest.html -*/ + @test + @bug 6176814 8132766 + @summary Metalworks frame maximizes after the move + @run main MaximizedFrameTest + */ -import java.applet.Applet; -import javax.swing.*; -import java.awt.event.*; -import java.awt.*; +import java.awt.AWTException; +import java.awt.Component; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JFrame; +import javax.swing.JLayeredPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; -public class MaximizedFrameTest extends Applet -{ - final int ITERATIONS_COUNT = 20; - Robot robot; - Point framePosition; - Point newFrameLocation; - JFrame frame; - Rectangle gcBounds; - public static Object LOCK = new Object(); +public class MaximizedFrameTest { - public void init() - { - String[] instructions = - { - "This is an AUTOMATIC test", - "simply wait until it is done" - }; + final static int ITERATIONS_COUNT = 5; + private static JFrame frame; + private static Point tempMousePosition; + private static Component titleComponent; + + public void init() { JFrame.setDefaultLookAndFeelDecorated(true); + + try { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + } catch (ClassNotFoundException | InstantiationException | + IllegalAccessException | UnsupportedLookAndFeelException ex) { + throw new RuntimeException("Test Failed. MetalLookAndFeel not set " + + "for frame"); + } + frame = new JFrame("JFrame Maximization Test"); frame.pack(); frame.setSize(450, 260); - }//End init() - - public void start () - { frame.setVisible(true); - validate(); - JLayeredPane lPane = frame.getLayeredPane(); - // System.out.println("JFrame's LayeredPane " + lPane ); - Component titleComponent = null; - boolean titleFound = false; - for (int j=0; j < lPane.getComponentsInLayer(JLayeredPane.FRAME_CONTENT_LAYER.intValue()).length; j++){ - titleComponent = lPane.getComponentsInLayer(JLayeredPane.FRAME_CONTENT_LAYER.intValue())[j]; - if (titleComponent.getClass().getName().equals("javax.swing.plaf.metal.MetalTitlePane")){ - titleFound = true; - break; + } + + public void getTitleComponent() throws Exception { + + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + JLayeredPane lPane = frame.getLayeredPane(); + boolean titleFound = false; + + for (int j = 0; j < lPane.getComponentsInLayer( + JLayeredPane.FRAME_CONTENT_LAYER.intValue()).length; j++) { + + titleComponent = lPane.getComponentsInLayer( + JLayeredPane.FRAME_CONTENT_LAYER.intValue())[j]; + + if (titleComponent.getClass().getName().equals( + "javax.swing.plaf.metal.MetalTitlePane")) { + + titleFound = true; + break; + } + } + + if (!titleFound) { + try { + dispose(); + } catch (Exception ex) { + Logger.getLogger(MaximizedFrameTest.class.getName()) + .log(Level.SEVERE, null, ex); + } + throw new RuntimeException("Test Failed. Unable to " + + "determine title component"); + } } - } - if ( !titleFound ){ - throw new RuntimeException("Test Failed. Unable to determine title's size."); - } - //-------------------------------- - // it is sufficient to get maximized Frame only once. - Point tempMousePosition; - framePosition = frame.getLocationOnScreen(); + }); + } + + public void doMaximizeFrameTest() throws Exception { + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + Point framePosition = frame.getLocationOnScreen(); + + tempMousePosition = new Point(framePosition.x + + frame.getWidth() / 2, framePosition.y + + titleComponent.getHeight() / 2); + } + }); + try { - robot = new Robot(); - tempMousePosition = new Point(framePosition.x + - frame.getWidth()/2, - framePosition.y + - titleComponent.getHeight()/2); + Robot robot = new Robot(); robot.mouseMove(tempMousePosition.x, tempMousePosition.y); - for (int iteration=0; iteration < ITERATIONS_COUNT; iteration++){ + robot.waitForIdle(); + + for (int iteration = 0; iteration < ITERATIONS_COUNT; iteration++) { robot.mousePress(InputEvent.BUTTON1_MASK); - gcBounds = - GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[0].getConfigurations()[0].getBounds(); - //Moving a mouse pointer less than a few pixels - //leads to rising a double click event. - //We have to use exceeded the AWT_MULTICLICK_SMUDGE - //const value (which is 4 by default on GNOME) to test that. + robot.waitForIdle(); + + // Moving a mouse pointer less than a few pixels + // leads to rising a double click event. + // We have to use exceeded the AWT_MULTICLICK_SMUDGE + // const value (which is 4 by default on GNOME) to test that. tempMousePosition.x += 5; robot.mouseMove(tempMousePosition.x, tempMousePosition.y); - robot.delay(70); + robot.waitForIdle(); robot.mouseRelease(InputEvent.BUTTON1_MASK); - if ( frame.getExtendedState() != 0 ){ - throw new RuntimeException ("Test failed. JFrame was maximized. ExtendedState is : "+frame.getExtendedState()); - } - robot.delay(500); - } //for iteration + robot.waitForIdle(); - }catch(AWTException e) { - throw new RuntimeException("Test Failed. AWTException thrown."); + if (frame.getExtendedState() != 0) { + dispose(); + throw new RuntimeException("Test failed. JFrame was " + + "maximized. ExtendedState is : " + + frame.getExtendedState()); + } } + } catch (AWTException e) { + dispose(); + throw new RuntimeException("Test Failed. AWTException thrown."); + } System.out.println("Test passed."); - }// start() -}// class + } + + private void dispose() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + if (null != frame) { + frame.dispose(); + } + } + }); + } + + public static void main(String[] args) throws Exception { + + MaximizedFrameTest maximizedFrameTest = new MaximizedFrameTest(); + maximizedFrameTest.init(); + maximizedFrameTest.getTitleComponent(); + maximizedFrameTest.doMaximizeFrameTest(); + maximizedFrameTest.dispose(); + } +} From 39b6389c6da36985bead96afefc1c68a5fcd2690 Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 1 Dec 2015 19:21:40 +0300 Subject: [PATCH 009/215] 8030702: Deadlock between subclass of AbstractDocument and UndoManager Reviewed-by: alexsch, azvegint --- .../javax/swing/text/AbstractDocument.java | 88 +++++++++++++ .../classes/javax/swing/undo/UndoManager.java | 119 +++++++++++++---- .../swing/text/UndoableEditLockSupport.java | 43 ++++++ .../AbstractDocumentUndoConcurrentTest.java | 122 ++++++++++++++++++ 4 files changed, 346 insertions(+), 26 deletions(-) create mode 100644 jdk/src/java.desktop/share/classes/sun/swing/text/UndoableEditLockSupport.java create mode 100644 jdk/test/javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java b/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java index 2b87618abd9..b965ccfcbc0 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java @@ -36,6 +36,7 @@ import javax.swing.tree.TreeNode; import sun.font.BidiUtils; import sun.swing.SwingUtilities2; +import sun.swing.text.UndoableEditLockSupport; /** * An implementation of the document interface to serve as a @@ -275,6 +276,11 @@ public abstract class AbstractDocument implements Document, Serializable { * @see EventListenerList */ protected void fireUndoableEditUpdate(UndoableEditEvent e) { + if (e.getEdit() instanceof DefaultDocumentEvent) { + e = new UndoableEditEvent(e.getSource(), + new DefaultDocumentEventUndoableWrapper( + (DefaultDocumentEvent)e.getEdit())); + } // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying @@ -2952,6 +2958,88 @@ public abstract class AbstractDocument implements Document, Serializable { } + static class DefaultDocumentEventUndoableWrapper implements + UndoableEdit, UndoableEditLockSupport + { + final DefaultDocumentEvent dde; + public DefaultDocumentEventUndoableWrapper(DefaultDocumentEvent dde) { + this.dde = dde; + } + + @Override + public void undo() throws CannotUndoException { + dde.undo(); + } + + @Override + public boolean canUndo() { + return dde.canUndo(); + } + + @Override + public void redo() throws CannotRedoException { + dde.redo(); + } + + @Override + public boolean canRedo() { + return dde.canRedo(); + } + + @Override + public void die() { + dde.die(); + } + + @Override + public boolean addEdit(UndoableEdit anEdit) { + return dde.addEdit(anEdit); + } + + @Override + public boolean replaceEdit(UndoableEdit anEdit) { + return dde.replaceEdit(anEdit); + } + + @Override + public boolean isSignificant() { + return dde.isSignificant(); + } + + @Override + public String getPresentationName() { + return dde.getPresentationName(); + } + + @Override + public String getUndoPresentationName() { + return dde.getUndoPresentationName(); + } + + @Override + public String getRedoPresentationName() { + return dde.getRedoPresentationName(); + } + + /** + * {@inheritDoc} + * @since 1.9 + */ + @Override + public void lockEdit() { + ((AbstractDocument)dde.getDocument()).writeLock(); + } + + /** + * {@inheritDoc} + * @since 1.9 + */ + @Override + public void unlockEdit() { + ((AbstractDocument)dde.getDocument()).writeUnlock(); + } + } + /** * This event used when firing document changes while Undo/Redo * operations. It just wraps DefaultDocumentEvent and delegates diff --git a/jdk/src/java.desktop/share/classes/javax/swing/undo/UndoManager.java b/jdk/src/java.desktop/share/classes/javax/swing/undo/UndoManager.java index 782dd3b3356..cb85826e611 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/undo/UndoManager.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/undo/UndoManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -28,6 +28,7 @@ package javax.swing.undo; import javax.swing.event.*; import javax.swing.UIManager; import java.util.*; +import sun.swing.text.UndoableEditLockSupport; /** * {@code UndoManager} manages a list of {@code UndoableEdits}, @@ -134,6 +135,11 @@ import java.util.*; */ @SuppressWarnings("serial") // Same-version serialization only public class UndoManager extends CompoundEdit implements UndoableEditListener { + private enum Action { + UNDO, + REDO, + ANY + } int indexOfNextAdd; int limit; @@ -369,13 +375,8 @@ public class UndoManager extends CompoundEdit implements UndoableEditListener { * @throws CannotRedoException if one of the edits throws * CannotRedoException */ - public synchronized void undoOrRedo() throws CannotRedoException, - CannotUndoException { - if (indexOfNextAdd == edits.size()) { - undo(); - } else { - redo(); - } + public void undoOrRedo() throws CannotRedoException, CannotUndoException { + tryUndoOrRedo(Action.ANY); } /** @@ -407,16 +408,8 @@ public class UndoManager extends CompoundEdit implements UndoableEditListener { * @see #canUndo * @see #editToBeUndone */ - public synchronized void undo() throws CannotUndoException { - if (inProgress) { - UndoableEdit edit = editToBeUndone(); - if (edit == null) { - throw new CannotUndoException(); - } - undoTo(edit); - } else { - super.undo(); - } + public void undo() throws CannotUndoException { + tryUndoOrRedo(Action.UNDO); } /** @@ -452,16 +445,90 @@ public class UndoManager extends CompoundEdit implements UndoableEditListener { * @see #canRedo * @see #editToBeRedone */ - public synchronized void redo() throws CannotRedoException { - if (inProgress) { - UndoableEdit edit = editToBeRedone(); - if (edit == null) { - throw new CannotRedoException(); + public void redo() throws CannotRedoException { + tryUndoOrRedo(Action.REDO); + } + + private void tryUndoOrRedo(Action action) { + UndoableEditLockSupport lockSupport = null; + boolean undo; + synchronized (this) { + if (action == Action.ANY) { + undo = indexOfNextAdd == edits.size(); + } else { + undo = action == Action.UNDO; + } + if (inProgress) { + UndoableEdit edit = undo ? editToBeUndone() : editToBeRedone(); + if (edit == null) { + throw undo ? new CannotUndoException() : + new CannotRedoException(); + } + lockSupport = getEditLockSupport(edit); + if (lockSupport == null) { + if (undo) { + undoTo(edit); + } else { + redoTo(edit); + } + return; + } + } else { + if (undo) { + super.undo(); + } else { + super.redo(); + } + return; } - redoTo(edit); - } else { - super.redo(); } + // the edit synchronization is required + while (true) { + lockSupport.lockEdit(); + UndoableEditLockSupport editLockSupport = null; + try { + synchronized (this) { + if (action == Action.ANY) { + undo = indexOfNextAdd == edits.size(); + } + if (inProgress) { + UndoableEdit edit = undo ? editToBeUndone() : + editToBeRedone(); + if (edit == null) { + throw undo ? new CannotUndoException() : + new CannotRedoException(); + } + editLockSupport = getEditLockSupport(edit); + if (editLockSupport == null || + editLockSupport == lockSupport) { + if (undo) { + undoTo(edit); + } else { + redoTo(edit); + } + return; + } + } else { + if (undo) { + super.undo(); + } else { + super.redo(); + } + return; + } + } + } finally { + if (lockSupport != null) { + lockSupport.unlockEdit(); + } + lockSupport = editLockSupport; + } + } + } + + private UndoableEditLockSupport getEditLockSupport(UndoableEdit anEdit) { + return anEdit instanceof UndoableEditLockSupport ? + (UndoableEditLockSupport)anEdit : null; } /** diff --git a/jdk/src/java.desktop/share/classes/sun/swing/text/UndoableEditLockSupport.java b/jdk/src/java.desktop/share/classes/sun/swing/text/UndoableEditLockSupport.java new file mode 100644 index 00000000000..43440da0dc8 --- /dev/null +++ b/jdk/src/java.desktop/share/classes/sun/swing/text/UndoableEditLockSupport.java @@ -0,0 +1,43 @@ +/* + * 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. 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.swing.text; + +import javax.swing.undo.UndoableEdit; + +/** + * UndoableEdit support for undo/redo actions synchronization + * @since 1.9 + */ +public interface UndoableEditLockSupport extends UndoableEdit { + /** + * lock the UndoableEdit for threadsafe undo/redo + */ + void lockEdit(); + + /** + * unlock the UndoableEdit + */ + void unlockEdit(); +} diff --git a/jdk/test/javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java b/jdk/test/javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java new file mode 100644 index 00000000000..30c48df47f8 --- /dev/null +++ b/jdk/test/javax/swing/undo/UndoManager/AbstractDocumentUndoConcurrentTest.java @@ -0,0 +1,122 @@ +/* + * 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 8030702 + @summary Deadlock between subclass of AbstractDocument and UndoManager + @author Semyon Sadetsky + */ + +import javax.swing.text.PlainDocument; +import javax.swing.text.StringContent; +import javax.swing.undo.UndoManager; +import java.text.DecimalFormat; +import java.text.Format; +import java.util.concurrent.CyclicBarrier; + +public class AbstractDocumentUndoConcurrentTest { + static CyclicBarrier barrier = new CyclicBarrier(3); + + private static PlainDocument doc1; + private static PlainDocument doc2; + private static Format format1 = new DecimalFormat(""); + private static Format format2 = new DecimalFormat(""); + + public static void main(String[] args) throws Exception { + test(); + System.out.println(doc1.getText(0, doc1.getLength())); + System.out.println(doc2.getText(0, doc2.getLength())); + System.out.println("ok"); + } + + private static void test() throws Exception { + doc1 = new PlainDocument(new StringContent()); + final UndoManager undoManager = new UndoManager(); + + doc1.addUndoableEditListener(undoManager); + doc1.insertString(0, "", null); + + doc2 = new PlainDocument(new StringContent()); + + doc2.addUndoableEditListener(undoManager); + doc2.insertString(0, "", null); + + Thread t1 = new Thread("Thread doc1") { + @Override + public void run() { + try { + barrier.await(); + for (int i = 0; i < 1000; i++) { + doc1.insertString(0, format1.format(i), null); + if(doc1.getLength() > 100) doc1.remove(0, 12); + } + + } catch (Exception e) { + throw new RuntimeException(e); + } + System.out.println("t1 done"); + } + }; + + Thread t2 = new Thread("Thread doc2") { + @Override + public void run() { + try { + barrier.await(); + for (int i = 0; i < 1000; i++) { + doc2.insertString(0, format2.format(i), null); + if(doc2.getLength() > 100) doc2.remove(0, 13); + } + + } catch (Exception e) { + throw new RuntimeException(e); + } + System.out.println("t2 done"); + } + }; + + Thread t3 = new Thread("Undo/Redo Thread") { + @Override + public void run() { + try { + barrier.await(); + } catch (Exception e) { + e.printStackTrace(); + } + for (int i = 0; i < 1000; i++) { + undoManager.undoOrRedo(); + undoManager.undo(); + } + System.out.println("t3 done"); + } + }; + + t1.start(); + t2.start(); + t3.start(); + + t1.join(); + t2.join(); + t3.join(); + } +} From e300345cc8e854f9ad7fe5347d4fe07ec93cfc9c Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 2 Dec 2015 00:34:35 +0530 Subject: [PATCH 010/215] 8074967: [macosx] JPEGImageReader incorrectly identifies YCbCr JPEGs as RGB in standard metadata Reviewed-by: prr, psadhukhan --- .../imageio/plugins/jpeg/JPEGMetadata.java | 12 +-- .../jpeg/JpegMetadataColorSpaceTest.java | 69 ++++++++++++++++++ .../javax/imageio/plugins/jpeg/nomarkers.jpg | Bin 0 -> 548 bytes 3 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 jdk/test/javax/imageio/plugins/jpeg/JpegMetadataColorSpaceTest.java create mode 100644 jdk/test/javax/imageio/plugins/jpeg/nomarkers.jpg diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java index f25863955ec..7975efda580 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGMetadata.java @@ -874,13 +874,13 @@ public class JPEGMetadata extends IIOMetadata implements Cloneable { return chroma; } - boolean idsAreJFIF = true; + boolean idsAreJFIF = false; - for (int i = 0; i < sof.componentSpecs.length; i++) { - int id = sof.componentSpecs[i].componentId; - if ((id < 1) || (id >= sof.componentSpecs.length)) { - idsAreJFIF = false; - } + int cid0 = sof.componentSpecs[0].componentId; + int cid1 = sof.componentSpecs[1].componentId; + int cid2 = sof.componentSpecs[2].componentId; + if ((cid0 == 1) && (cid1 == 2) && (cid2 == 3)) { + idsAreJFIF = true; } if (idsAreJFIF) { diff --git a/jdk/test/javax/imageio/plugins/jpeg/JpegMetadataColorSpaceTest.java b/jdk/test/javax/imageio/plugins/jpeg/JpegMetadataColorSpaceTest.java new file mode 100644 index 00000000000..dbe54f553e2 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/jpeg/JpegMetadataColorSpaceTest.java @@ -0,0 +1,69 @@ +/* + * 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 8074967 + * @summary Test verifies if there is no JFIF & EXIF header + * and sampling factor is same of JPEG image, then + * JPEG colorspace should not be RGB. + * @run main JpegMetadataColorSpaceTest + */ + +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.metadata.IIOMetadataFormatImpl; +import javax.imageio.metadata.IIOMetadataNode; +import javax.imageio.stream.ImageInputStream; +import java.io.File; +import java.io.IOException; +import java.util.Iterator; + +public class JpegMetadataColorSpaceTest { + public static void main(String[] args) throws IOException { + String fileName = "nomarkers.jpg"; + String sep = System.getProperty("file.separator"); + String dir = System.getProperty("test.src", "."); + String filePath = dir+sep+fileName; + System.out.println("Test file: " + filePath); + File file = new File(filePath); + ImageInputStream stream = ImageIO.createImageInputStream(file); + Iterator readers = ImageIO.getImageReaders(stream); + + if(readers.hasNext()) { + ImageReader reader = readers.next(); + reader.setInput(stream); + IIOMetadata metadata = reader.getImageMetadata(0); + + IIOMetadataNode standardTree = (IIOMetadataNode) + metadata.getAsTree + (IIOMetadataFormatImpl.standardMetadataFormatName); + IIOMetadataNode colorSpaceType = (IIOMetadataNode) + standardTree.getElementsByTagName("ColorSpaceType").item(0); + String colorSpaceName = colorSpaceType.getAttribute("name"); + if(colorSpaceName.equals("RGB")) + throw new RuntimeException("Identified incorrect ColorSpace"); + } + } +} diff --git a/jdk/test/javax/imageio/plugins/jpeg/nomarkers.jpg b/jdk/test/javax/imageio/plugins/jpeg/nomarkers.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3b08cdd3b02b159411cd54e30c2683be6d8ca6b0 GIT binary patch literal 548 zcmb79+YN#+6uq~lP-wvxTjbZoJs|PRE!@N%9K$h;L--h`wjq+BJmSgu>CJi7-Q5fJ zKnV%-h&&l*EQ(l`Br%tnlp+%%FG`gcx)4HDO0SKzR<1U6W$Myc6GD)BPsCEjQj?3^ z{0(;n&7p;sq6VUoYIHZSfCxiye>Oi?a8HmFfhei~@X`)V{p%Fm>O1r3-P~s)Bcavk saREhaa85va!DL0;bQO~VY_|CM3{XE@oe#TFE-Y0`OFO~L5HEPV0ZWiZasU7T literal 0 HcmV?d00001 From 3a2b32b7076804276dbe02c4f9d11ee20bcc981e Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 2 Dec 2015 00:47:36 +0530 Subject: [PATCH 011/215] 6967419: IndexOutOfBoundsException when drawing PNGs Reviewed-by: prr, psadhukhan --- .../imageio/plugins/png/PNGImageWriter.java | 12 ++- .../plugins/png/PngForceStopWritingTest.java | 76 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 jdk/test/javax/imageio/plugins/png/PngForceStopWritingTest.java diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java index 0004904aa99..278882e5385 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java @@ -193,7 +193,17 @@ final class IDATOutputStream extends ImageOutputStreamImpl { // Return to end of chunk and flush to minimize buffering stream.seek(pos); - stream.flushBefore(pos); + try { + stream.flushBefore(pos); + } catch (IOException e) { + /* + * If flushBefore() fails we try to access startPos in finally + * block of write_IDAT(). We should update startPos to avoid + * IndexOutOfBoundException while seek() is happening. + */ + this.startPos = stream.getStreamPosition(); + throw e; + } } public int read() throws IOException { diff --git a/jdk/test/javax/imageio/plugins/png/PngForceStopWritingTest.java b/jdk/test/javax/imageio/plugins/png/PngForceStopWritingTest.java new file mode 100644 index 00000000000..b2da248787c --- /dev/null +++ b/jdk/test/javax/imageio/plugins/png/PngForceStopWritingTest.java @@ -0,0 +1,76 @@ +/* + * 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 6967419 + * @summary Test verifies that when we force stop PNG writing to + * ImageOutputStream, it should not cause IndexOutOfBoundException. + * @run main PngForceStopWritingTest + */ + +import java.awt.Color; +import java.awt.GradientPaint; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.OutputStream; +import javax.imageio.ImageIO; +import javax.imageio.stream.ImageOutputStream; + +public class PngForceStopWritingTest { + + public static void main(String[] args) throws IOException { + + OutputStream outputStream = new NullOutputStream(); + ImageOutputStream imageOutputStream = + ImageIO.createImageOutputStream(outputStream); + try { + ImageIO.write(createImage(2048),"PNG", imageOutputStream); + } catch (IOException e) { + imageOutputStream.close(); + } + } + + private static BufferedImage createImage(int size) { + + BufferedImage image = new + BufferedImage(size, size, BufferedImage.TYPE_3BYTE_BGR); + Graphics2D g = image.createGraphics(); + g.setPaint(new GradientPaint(0, 0, Color.blue, size, size, Color.red)); + g.fillRect(0, 0, size, size); + g.dispose(); + return image; + } + + static class NullOutputStream extends OutputStream { + long count = 0; + @Override + public void write(int b) throws IOException { + count++; + if (count > 30000L) { + throw new IOException("Force stop image writing"); + } + } + } +} From 2b89c8529ddb210492786b533435521fa9eef559 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 2 Dec 2015 00:52:49 +0530 Subject: [PATCH 012/215] 8041501: ImageIO reader is not capable of reading JPEGs without JFIF header Reviewed-by: prr, psadhukhan --- .../share/native/libjavajpeg/imageioJPEG.c | 30 ++++---- .../plugins/jpeg/JpegImageColorSpaceTest.java | 69 +++++++++++++++++++ 2 files changed, 86 insertions(+), 13 deletions(-) create mode 100644 jdk/test/javax/imageio/plugins/jpeg/JpegImageColorSpaceTest.java diff --git a/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c b/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c index f0d5c019a8d..81fe9117d04 100644 --- a/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c +++ b/jdk/src/java.desktop/share/native/libjavajpeg/imageioJPEG.c @@ -1610,6 +1610,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader int ret; int h_samp0, h_samp1, h_samp2; int v_samp0, v_samp1, v_samp2; + int cid0, cid1, cid2; jboolean retval = JNI_FALSE; imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr); j_decompress_ptr cinfo; @@ -1711,17 +1712,15 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader } } else if (!cinfo->saw_JFIF_marker && !IS_EXIF(cinfo)) { /* - * IJG assumes all unidentified 3-channels are YCbCr. - * We assume that only if the second two channels are - * subsampled (either horizontally or vertically). If not, - * we assume RGB. - * - * 4776576: Some digital cameras output YCbCr JPEG images - * that do not contain a JFIF APP0 marker but are only - * vertically subsampled (no horizontal subsampling). - * We should only assume this is RGB data if the subsampling - * factors for the second two channels are the same as the - * first (check both horizontal and vertical factors). + * In the absence of certain markers, IJG has interpreted + * component id's of [1,2,3] as meaning YCbCr.We follow that + * interpretation, which is additionally described in the Image + * I/O JPEG metadata spec.If that condition is not met here the + * next step will be to examine the subsampling factors, if + * there is any difference in subsampling factors we also assume + * YCbCr, only if both horizontal and vertical subsampling + * is same we assume JPEG color space as RGB. + * This is also described in the Image I/O JPEG metadata spec. */ h_samp0 = cinfo->comp_info[0].h_samp_factor; h_samp1 = cinfo->comp_info[1].h_samp_factor; @@ -1731,8 +1730,13 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_readImageHeader v_samp1 = cinfo->comp_info[1].v_samp_factor; v_samp2 = cinfo->comp_info[2].v_samp_factor; - if ((h_samp1 == h_samp0) && (h_samp2 == h_samp0) && - (v_samp1 == v_samp0) && (v_samp2 == v_samp0)) + cid0 = cinfo->comp_info[0].component_id; + cid1 = cinfo->comp_info[1].component_id; + cid2 = cinfo->comp_info[2].component_id; + + if ((!(cid0 == 1 && cid1 == 2 && cid2 == 3)) && + ((h_samp1 == h_samp0) && (h_samp2 == h_samp0) && + (v_samp1 == v_samp0) && (v_samp2 == v_samp0))) { cinfo->jpeg_color_space = JCS_RGB; /* output is already RGB, so it stays the same */ diff --git a/jdk/test/javax/imageio/plugins/jpeg/JpegImageColorSpaceTest.java b/jdk/test/javax/imageio/plugins/jpeg/JpegImageColorSpaceTest.java new file mode 100644 index 00000000000..c18b8216120 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/jpeg/JpegImageColorSpaceTest.java @@ -0,0 +1,69 @@ +/* + * 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 8041501 + * @summary Test verifies if there is no JFIF & EXIF header + * and sampling factor is same of JPEG image, then + * imageIO should not override colorspace determined + * in IJG library. + * @run main JpegImageColorSpaceTest + */ + +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.io.File; +import javax.imageio.ImageIO; + +public class JpegImageColorSpaceTest { + + public static void main(String args[]) throws Exception { + + String fileName = "nomarkers.jpg"; + String sep = System.getProperty("file.separator"); + String dir = System.getProperty("test.src", "."); + String filePath = dir+sep+fileName; + System.out.println("Test file: " + filePath); + File imageFile = new File(filePath); + + BufferedImage bufferedImage = ImageIO.read(imageFile); + int imageWidth = bufferedImage.getWidth(); + int imageHeight = bufferedImage.getHeight(); + + for (int i = 0; i < imageWidth; i++) { + for(int j = 0; j < imageHeight; j++) { + /* + * Since image is white we check individual pixel values from + * BufferedImage to verify if ImageIO.read() is done with proper + * color space or not. + */ + if (bufferedImage.getRGB(i, j) != Color.white.getRGB()) { + // color space is not proper + throw new RuntimeException("ColorSpace is not determined " + + "properly by ImageIO"); + } + } + } + } +} From 7925eb298bb356873c48c820f9741aa391979bad Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 2 Dec 2015 15:13:42 +0100 Subject: [PATCH 013/215] 8134883: C1 hard crash in range check elimination in Nashorn test262parallel C1's range check elimination breaks with a non-natural loop that has an exception handler as one entry Reviewed-by: iveresov --- hotspot/src/share/vm/c1/c1_IR.cpp | 7 +- .../TestRangeCheckExceptionHandlerLoop.jasm | 89 +++++++++++++++++++ ...estRangeCheckExceptionHandlerLoopMain.java | 41 +++++++++ 3 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoop.jasm create mode 100644 hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoopMain.java diff --git a/hotspot/src/share/vm/c1/c1_IR.cpp b/hotspot/src/share/vm/c1/c1_IR.cpp index 6b015b44d85..105d27fcc0c 100644 --- a/hotspot/src/share/vm/c1/c1_IR.cpp +++ b/hotspot/src/share/vm/c1/c1_IR.cpp @@ -579,11 +579,8 @@ void ComputeLinearScanOrder::count_edges(BlockBegin* cur, BlockBegin* parent) { assert(is_visited(cur), "block must be visisted when block is active"); assert(parent != NULL, "must have parent"); - cur->set(BlockBegin::linear_scan_loop_header_flag); cur->set(BlockBegin::backward_branch_target_flag); - parent->set(BlockBegin::linear_scan_loop_end_flag); - // When a loop header is also the start of an exception handler, then the backward branch is // an exception edge. Because such edges are usually critical edges which cannot be split, the // loop must be excluded here from processing. @@ -592,6 +589,10 @@ void ComputeLinearScanOrder::count_edges(BlockBegin* cur, BlockBegin* parent) { _iterative_dominators = true; return; } + + cur->set(BlockBegin::linear_scan_loop_header_flag); + parent->set(BlockBegin::linear_scan_loop_end_flag); + assert(parent->number_of_sux() == 1 && parent->sux_at(0) == cur, "loop end blocks must have one successor (critical edges are split)"); diff --git a/hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoop.jasm b/hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoop.jasm new file mode 100644 index 00000000000..2befe6db091 --- /dev/null +++ b/hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoop.jasm @@ -0,0 +1,89 @@ +/* + * 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. + * + */ + +super public class TestRangeCheckExceptionHandlerLoop + version 51:0 +{ + + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + +/* This method has an irreducible loop, with 2 entries, one is the exception handler + + static void test(boolean flag, int[] array, Exception exception) throws Exception { + int i = 0; + if (flag) { + try { + throw exception; + } catch(Exception e) { + array[i] = 0; + i++; + } + } + if (i < 10) { + throw exception; // caught by exception handler above as well + } + } +*/ +public static Method test:"(Z[ILjava/lang/Exception;)V" + throws java/lang/Exception + stack 3 locals 5 +{ + iconst_0; + istore_3; + iload_0; + ifeq L17; + try t0; + aload_2; + athrow; + endtry t0; + catch t0 java/lang/Exception; + catch t1 java/lang/Exception; + stack_frame_type full; + locals_map int, class "[I", class java/lang/Exception, int; + stack_map class java/lang/Exception; + astore 4; + aload_1; + iload_3; + iconst_0; + iastore; + iinc 3, 1; + L17: stack_frame_type same; + iload_3; + bipush 10; + if_icmpge L25; + try t1; + aload_2; + athrow; + endtry t1; + L25: stack_frame_type same; + return; +} +} // end Class TestRangeCheckExceptionHandlerLoop diff --git a/hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoopMain.java b/hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoopMain.java new file mode 100644 index 00000000000..3eac3231571 --- /dev/null +++ b/hotspot/test/compiler/rangechecks/TestRangeCheckExceptionHandlerLoopMain.java @@ -0,0 +1,41 @@ +/* + * 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 8134883 + * @summary C1's range check elimination breaks with a non-natural loop that an exception handler as one entry + * @compile TestRangeCheckExceptionHandlerLoop.jasm + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestRangeCheckExceptionHandlerLoopMain + */ + +public class TestRangeCheckExceptionHandlerLoopMain { + public static void main(String[] args) throws Exception { + Exception exception = new Exception(); + int[] array = new int[10]; + for (int i = 0; i < 20000; i++) { + TestRangeCheckExceptionHandlerLoop.test(false, array, exception); + } + } +} From 854c76518636eacf0496f971fc4fd75a7eed8e9f Mon Sep 17 00:00:00 2001 From: Jiri Vanek Date: Wed, 2 Dec 2015 21:23:59 +0000 Subject: [PATCH 014/215] 8144071: ImageIO does not reset stream if an exception is thrown Reset the I/O stream in a finally block Reviewed-by: andrew --- .../share/classes/javax/imageio/ImageIO.java | 9 +- .../imageio/spi/MarkTryFinallyReproducer.java | 367 ++++++++++++++++++ 2 files changed, 373 insertions(+), 3 deletions(-) create mode 100644 jdk/test/javax/imageio/spi/MarkTryFinallyReproducer.java diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java b/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java index 7beea7b77a6..b56975ba15b 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/ImageIO.java @@ -564,9 +564,12 @@ public final class ImageIO { if (stream != null) { stream.mark(); } - canDecode = spi.canDecodeInput(input); - if (stream != null) { - stream.reset(); + try { + canDecode = spi.canDecodeInput(input); + } finally { + if (stream != null) { + stream.reset(); + } } return canDecode; diff --git a/jdk/test/javax/imageio/spi/MarkTryFinallyReproducer.java b/jdk/test/javax/imageio/spi/MarkTryFinallyReproducer.java new file mode 100644 index 00000000000..7efd06a62f4 --- /dev/null +++ b/jdk/test/javax/imageio/spi/MarkTryFinallyReproducer.java @@ -0,0 +1,367 @@ +/* + * Copyright 2015 Red Hat, Inc. + * 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 8144071 + * @run main/othervm MarkTryFinallyReproducer + * @summary Test that call to canDecodeInput in ImageIO don't corrupt + * mark/reset stack in ImageInputStream + * @author Jiri Vanek + */ + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteOrder; +import java.util.Locale; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.spi.IIORegistry; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.stream.IIOByteBuffer; +import javax.imageio.stream.ImageInputStream; + + +public class MarkTryFinallyReproducer { + + private static final byte[] bmp = new byte[]{ + 127,127, 66, 77, -86, 0, 0, 0, 0, 0, 0, 0, + 122, 0, 0, 0, 108, 0, 0, 0, 4, 0, 0, 0, 4, + 0, 0, 0, 1, 0, 24, 0, 0, 0, 0, 0, 48, 0, 0, + 0, 19, 11, 0, 0, 19, 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 66, 71, 82, 115, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, -1, -1, + -1, -1, -1, 0, -1, 0, -1, -1, -1, -1, 0, 0, 0, -17, + 0, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, -1, -1, -1, + -1, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, -1 + }; + //first two are evil, we are skipping them later. Others are normal BMP + + private static class NotClosingImageInputStream implements ImageInputStream { + + private final ImageInputStream src; + + private NotClosingImageInputStream(ImageInputStream createImageInputStream) { + this.src = createImageInputStream; + } + + @Override + public void setByteOrder(ByteOrder byteOrder) { + src.setByteOrder(byteOrder); + } + + @Override + public ByteOrder getByteOrder() { + return src.getByteOrder(); + } + + @Override + public int read() throws IOException { + return src.read(); + } + + @Override + public int read(byte[] b) throws IOException { + return src.read(b); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + return src.read(b, off, len); + } + + @Override + public void readBytes(IIOByteBuffer buf, int len) throws IOException { + src.readBytes(buf, len); + } + + @Override + public boolean readBoolean() throws IOException { + return src.readBoolean(); + } + + @Override + public byte readByte() throws IOException { + return src.readByte(); + } + + @Override + public int readUnsignedByte() throws IOException { + return src.readUnsignedByte(); + } + + @Override + public short readShort() throws IOException { + return src.readShort(); + } + + @Override + public int readUnsignedShort() throws IOException { + return src.readUnsignedShort(); + } + + @Override + public char readChar() throws IOException { + return src.readChar(); + } + + @Override + public int readInt() throws IOException { + return src.readInt(); + } + + @Override + public long readUnsignedInt() throws IOException { + return src.readUnsignedInt(); + } + + @Override + public long readLong() throws IOException { + return src.readLong(); + } + + @Override + public float readFloat() throws IOException { + return src.readFloat(); + } + + @Override + public double readDouble() throws IOException { + return src.readDouble(); + } + + @Override + public String readLine() throws IOException { + return src.readLine(); + } + + @Override + public String readUTF() throws IOException { + return src.readUTF(); + } + + @Override + public void readFully(byte[] b, int off, int len) throws IOException { + src.readFully(b, off, len); + } + + @Override + public void readFully(byte[] b) throws IOException { + src.readFully(b); + } + + @Override + public void readFully(short[] s, int off, int len) throws IOException { + src.readFully(s, off, len); + } + + @Override + public void readFully(char[] c, int off, int len) throws IOException { + src.readFully(c, off, len); + } + + @Override + public void readFully(int[] i, int off, int len) throws IOException { + src.readFully(i, off, len); + } + + @Override + public void readFully(long[] l, int off, int len) throws IOException { + src.readFully(l, off, len); + } + + @Override + public void readFully(float[] f, int off, int len) throws IOException { + src.readFully(f, off, len); + } + + @Override + public void readFully(double[] d, int off, int len) throws IOException { + src.readFully(d, off, len); + } + + @Override + public long getStreamPosition() throws IOException { + return src.getStreamPosition(); + } + + @Override + public int getBitOffset() throws IOException { + return src.getBitOffset(); + } + + @Override + public void setBitOffset(int bitOffset) throws IOException { + src.setBitOffset(bitOffset); + } + + @Override + public int readBit() throws IOException { + return src.readBit(); + } + + @Override + public long readBits(int numBits) throws IOException { + return src.readBits(numBits); + } + + @Override + public long length() throws IOException { + return src.length(); + } + + @Override + public int skipBytes(int n) throws IOException { + return src.skipBytes(n); + } + + @Override + public long skipBytes(long n) throws IOException { + return src.skipBytes(n); + } + + @Override + public void seek(long pos) throws IOException { + src.seek(pos); + } + + @Override + public void mark() { + src.mark(); + } + + @Override + public void reset() throws IOException { + src.reset(); + } + + @Override + public void flushBefore(long pos) throws IOException { + src.flushBefore(pos); + } + + @Override + public void flush() throws IOException { + src.flush(); + } + + @Override + public long getFlushedPosition() { + return src.getFlushedPosition(); + } + + @Override + public boolean isCached() { + return src.isCached(); + } + + @Override + public boolean isCachedMemory() { + return src.isCachedMemory(); + } + + @Override + public boolean isCachedFile() { + return src.isCachedFile(); + } + + @Override + public void close() throws IOException { + //the only important one. nothing + } + } + + static final String readerClassName + = MarkTryFinallyReproducerSpi.class.getName(); + static final String[] localNames = {"myNames"}; + static final String[] localSuffixes = {"mySuffixes"}; + static final String[] localMIMETypes = {"myMimes"}; + + public static class MarkTryFinallyReproducerSpi extends ImageReaderSpi { + + public MarkTryFinallyReproducerSpi() { + super("MarkTryFinallyReproducerSpi", + "1.0", + localNames, + localSuffixes, + localMIMETypes, + readerClassName, + new Class[]{ImageInputStream.class}, + new String[0], + false, + null, + null, + new String[0], + new String[0], + false, + null, + null, + new String[0], + new String[0]); + } + + @Override + public String getDescription(Locale locale) { + return ""; + } + + @Override + public boolean canDecodeInput(Object input) throws IOException { + throw new IOException("Bad luck"); + } + + @Override + public ImageReader createReaderInstance(Object extension) { + return null; + } + } + + public static void main(String[] args) throws IOException { + MarkTryFinallyReproducerSpi spi = new MarkTryFinallyReproducerSpi(); + IIORegistry.getDefaultInstance().registerServiceProvider(spi); + + ImageInputStream iis1 = + new NotClosingImageInputStream(ImageIO.createImageInputStream(new ByteArrayInputStream(bmp))); + iis1.readByte(); + iis1.mark(); + long p1 = iis1.getStreamPosition(); + iis1.readByte(); + iis1.mark(); + long p2 = iis1.getStreamPosition(); + BufferedImage bi1 = ImageIO.read(iis1); + iis1.reset(); + long pn2 = iis1.getStreamPosition(); + iis1.reset(); + long pn1 = iis1.getStreamPosition(); + if (p1 != pn1 || p2!= pn2) { + throw new RuntimeException("Exception from call to canDecodeInput in ImageIO. " + + "Corrupted stack in ImageInputStream"); + } + + } + +} From 59accc606b6d79a8dba0a86d11fa92fa7e52cb23 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Thu, 3 Dec 2015 12:27:02 +0530 Subject: [PATCH 015/215] 8131754: AquaTreeUI.getCollapsedIcon() issue reported in java beans tests with a modular build Reviewed-by: malenkov, alexsch --- .../share/classes/javax/swing/JComponent.java | 1 + .../XMLEncoder/javax_swing_JComponent.java | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 jdk/test/java/beans/XMLEncoder/javax_swing_JComponent.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java b/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java index 3276d534a48..b6fa1b7bd81 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/JComponent.java @@ -618,6 +618,7 @@ public abstract class JComponent extends Container implements Serializable, * @return the {@code ComponentUI} object that renders this component * @since 1.9 */ + @Transient public ComponentUI getUI() { return ui; } diff --git a/jdk/test/java/beans/XMLEncoder/javax_swing_JComponent.java b/jdk/test/java/beans/XMLEncoder/javax_swing_JComponent.java new file mode 100644 index 00000000000..9ca11f9954a --- /dev/null +++ b/jdk/test/java/beans/XMLEncoder/javax_swing_JComponent.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; + +/* + * @test + * @bug 8131754 + * @summary Tests JComponent encoding + */ +public final class javax_swing_JComponent extends AbstractTest { + + public static void main(final String[] args) { + new javax_swing_JComponent().test(true); + } + + protected JComponent getObject() { + return new SimpleJComponent(); + } + + protected JComponent getAnotherObject() { + return new CustomJComponent(); + } + + public static final class SimpleJComponent extends JComponent { + + } + + public static final class CustomJComponent extends JComponent { + + public CustomJComponent() { + ui = new CustomUI(); + } + + @Override + public ComponentUI getUI() { + return ui; + } + + @Override + public void setUI(final ComponentUI newUI) { + ui = newUI; + } + } + + public static final class CustomUI extends ComponentUI { + + public boolean getFlag() { + throw new Error(); + } + + public void setFlag(final boolean flag) { + throw new Error(); + } + } +} From 67caeeaa08ca5174d6ca672c3a9004ecc43e0b69 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Mon, 7 Dec 2015 21:23:02 +0800 Subject: [PATCH 016/215] 8144587: aarch64: generate vectorized MLA/MLS instructions Add support for MLA/MLS (vector) instructions Reviewed-by: roland --- hotspot/src/cpu/aarch64/vm/aarch64.ad | 118 ++++++++++++++++++ .../src/cpu/aarch64/vm/assembler_aarch64.hpp | 2 + 2 files changed, 120 insertions(+) diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index 75b598e902c..b6a1a242038 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -15318,6 +15318,124 @@ instruct vmul2D(vecX dst, vecX src1, vecX src2) ins_pipe(pipe_class_default); %} +// --------------------------------- MLA -------------------------------------- + +instruct vmla4S(vecD dst, vecD src1, vecD src2) +%{ + predicate(n->as_Vector()->length() == 2 || + n->as_Vector()->length() == 4); + match(Set dst (AddVS dst (MulVS src1 src2))); + ins_cost(INSN_COST); + format %{ "mlav $dst,$src1,$src2\t# vector (4H)" %} + ins_encode %{ + __ mlav(as_FloatRegister($dst$$reg), __ T4H, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vmla8S(vecX dst, vecX src1, vecX src2) +%{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (AddVS dst (MulVS src1 src2))); + ins_cost(INSN_COST); + format %{ "mlav $dst,$src1,$src2\t# vector (8H)" %} + ins_encode %{ + __ mlav(as_FloatRegister($dst$$reg), __ T8H, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vmla2I(vecD dst, vecD src1, vecD src2) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (AddVI dst (MulVI src1 src2))); + ins_cost(INSN_COST); + format %{ "mlav $dst,$src1,$src2\t# vector (2S)" %} + ins_encode %{ + __ mlav(as_FloatRegister($dst$$reg), __ T2S, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vmla4I(vecX dst, vecX src1, vecX src2) +%{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (AddVI dst (MulVI src1 src2))); + ins_cost(INSN_COST); + format %{ "mlav $dst,$src1,$src2\t# vector (4S)" %} + ins_encode %{ + __ mlav(as_FloatRegister($dst$$reg), __ T4S, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +// --------------------------------- MLS -------------------------------------- + +instruct vmls4S(vecD dst, vecD src1, vecD src2) +%{ + predicate(n->as_Vector()->length() == 2 || + n->as_Vector()->length() == 4); + match(Set dst (SubVS dst (MulVS src1 src2))); + ins_cost(INSN_COST); + format %{ "mlsv $dst,$src1,$src2\t# vector (4H)" %} + ins_encode %{ + __ mlsv(as_FloatRegister($dst$$reg), __ T4H, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vmls8S(vecX dst, vecX src1, vecX src2) +%{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (SubVS dst (MulVS src1 src2))); + ins_cost(INSN_COST); + format %{ "mlsv $dst,$src1,$src2\t# vector (8H)" %} + ins_encode %{ + __ mlsv(as_FloatRegister($dst$$reg), __ T8H, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vmls2I(vecD dst, vecD src1, vecD src2) +%{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (SubVI dst (MulVI src1 src2))); + ins_cost(INSN_COST); + format %{ "mlsv $dst,$src1,$src2\t# vector (2S)" %} + ins_encode %{ + __ mlsv(as_FloatRegister($dst$$reg), __ T2S, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + +instruct vmls4I(vecX dst, vecX src1, vecX src2) +%{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (SubVI dst (MulVI src1 src2))); + ins_cost(INSN_COST); + format %{ "mlsv $dst,$src1,$src2\t# vector (4S)" %} + ins_encode %{ + __ mlsv(as_FloatRegister($dst$$reg), __ T4S, + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + ins_pipe(pipe_class_default); +%} + // --------------------------------- DIV -------------------------------------- instruct vdiv2F(vecD dst, vecD src1, vecD src2) diff --git a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp index dcd99c341ce..76fdf876f90 100644 --- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp @@ -2041,6 +2041,8 @@ public: INSN(addv, 0, 0b100001); INSN(subv, 1, 0b100001); INSN(mulv, 0, 0b100111); + INSN(mlav, 0, 0b100101); + INSN(mlsv, 1, 0b100101); INSN(sshl, 0, 0b010001); INSN(ushl, 1, 0b010001); From 73acd1827545f9011b44b86ab69c56b7302b4d46 Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Thu, 3 Dec 2015 11:18:34 +0100 Subject: [PATCH 017/215] 8144223: Move j.l.invoke.{ForceInline, DontInline, Stable} to jdk.internal.vm.annotation package Reviewed-by: jrose, vlivanov, mchung, roland --- .../src/jdk/vm/ci/hotspot/Stable.java | 2 +- hotspot/src/share/vm/classfile/classFileParser.cpp | 6 +++--- hotspot/src/share/vm/classfile/vmSymbols.hpp | 6 +++--- .../test/compiler/jsr292/NonInlinedCall/GCTest.java | 3 +++ .../compiler/jsr292/NonInlinedCall/InvokeTest.java | 3 +++ .../compiler/jsr292/NonInlinedCall/RedefineTest.java | 3 ++- hotspot/test/compiler/stable/TestStableBoolean.java | 2 ++ hotspot/test/compiler/stable/TestStableByte.java | 2 ++ hotspot/test/compiler/stable/TestStableChar.java | 2 ++ hotspot/test/compiler/stable/TestStableDouble.java | 2 ++ hotspot/test/compiler/stable/TestStableFloat.java | 2 ++ hotspot/test/compiler/stable/TestStableInt.java | 2 ++ hotspot/test/compiler/stable/TestStableLong.java | 2 ++ .../compiler/stable/TestStableMemoryBarrier.java | 2 ++ hotspot/test/compiler/stable/TestStableObject.java | 2 ++ hotspot/test/compiler/stable/TestStableShort.java | 2 ++ .../test/compiler/unsafe/UnsafeGetConstantField.java | 12 +++++++++--- 17 files changed, 44 insertions(+), 11 deletions(-) diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Stable.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Stable.java index e386dc0ca77..f313238bf41 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Stable.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Stable.java @@ -29,7 +29,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * This annotation functions as an alias for the java.lang.invoke.Stable annotation within JVMCI + * This annotation functions as an alias for the jdk.internal.vm.annotation.Stable annotation within JVMCI * code. It is specially recognized during class file parsing in the same way as that annotation. */ @Target(ElementType.FIELD) diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index aa788362bc7..184744e5481 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -1733,11 +1733,11 @@ ClassFileParser::AnnotationCollector::annotation_index(ClassLoaderData* loader_d if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_CallerSensitive; - case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_ForceInline_signature): + case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_ForceInline_signature): if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_ForceInline; - case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_DontInline_signature): + case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_DontInline_signature): if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_DontInline; @@ -1763,7 +1763,7 @@ ClassFileParser::AnnotationCollector::annotation_index(ClassLoaderData* loader_d if (!privileged) break; // only allow in privileged code return _field_Stable; #endif - case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_Stable_signature): + case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_Stable_signature): if (_location != _in_field) break; // only allow for fields if (!privileged) break; // only allow in privileged code return _field_Stable; diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index e651ad00ed9..2c1f2572e85 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -268,6 +268,9 @@ \ /* Intrinsic Annotation (JDK 9 and above) */ \ template(jdk_internal_HotSpotIntrinsicCandidate_signature, "Ljdk/internal/HotSpotIntrinsicCandidate;") \ + template(jdk_internal_vm_annotation_ForceInline_signature, "Ljdk/internal/vm/annotation/ForceInline;") \ + template(jdk_internal_vm_annotation_DontInline_signature, "Ljdk/internal/vm/annotation/DontInline;") \ + template(jdk_internal_vm_annotation_Stable_signature, "Ljdk/internal/vm/annotation/Stable;") \ \ /* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \ template(java_lang_invoke_CallSite, "java/lang/invoke/CallSite") \ @@ -286,10 +289,7 @@ template(java_lang_invoke_MethodHandleNatives, "java/lang/invoke/MethodHandleNatives") \ template(java_lang_invoke_MethodHandleNatives_CallSiteContext, "java/lang/invoke/MethodHandleNatives$CallSiteContext") \ template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \ - template(java_lang_invoke_ForceInline_signature, "Ljava/lang/invoke/ForceInline;") \ - template(java_lang_invoke_DontInline_signature, "Ljava/lang/invoke/DontInline;") \ template(java_lang_invoke_InjectedProfile_signature, "Ljava/lang/invoke/InjectedProfile;") \ - template(java_lang_invoke_Stable_signature, "Ljava/lang/invoke/Stable;") \ template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \ template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;") \ template(java_lang_invoke_MethodHandleNatives_CallSiteContext_signature, "Ljava/lang/invoke/MethodHandleNatives$CallSiteContext;") \ diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java index 0a325734db4..8be925b00d6 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java @@ -41,6 +41,9 @@ package java.lang.invoke; import sun.hotspot.WhiteBox; +import jdk.internal.vm.annotation.DontInline; +import jdk.internal.vm.annotation.Stable; + import java.lang.ref.*; import static jdk.test.lib.Asserts.*; diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java index 687ef7242a7..8ab6031b575 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java @@ -43,6 +43,9 @@ package java.lang.invoke; import sun.hotspot.WhiteBox; + +import jdk.internal.vm.annotation.DontInline; + import static jdk.test.lib.Asserts.*; public class InvokeTest { diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java index 54ce2221390..2da0f4bd70b 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java @@ -44,6 +44,7 @@ import sun.hotspot.WhiteBox; import sun.misc.Unsafe; import jdk.internal.org.objectweb.asm.*; +import jdk.internal.vm.annotation.DontInline; import java.lang.instrument.ClassDefinition; import java.lang.instrument.Instrumentation; @@ -73,7 +74,7 @@ public class RedefineTest { cw.visit(52, ACC_PUBLIC | ACC_SUPER, NAME, null, "java/lang/Object", null); { mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f", "()I", null, null); - mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true); + mv.visitAnnotation("Ljdk/internal/vm/annotation/DontInline;", true); mv.visitCode(); mv.visitLdcInsn(r); mv.visitInsn(IRETURN); diff --git a/hotspot/test/compiler/stable/TestStableBoolean.java b/hotspot/test/compiler/stable/TestStableBoolean.java index 767055752b1..168ddf48da7 100644 --- a/hotspot/test/compiler/stable/TestStableBoolean.java +++ b/hotspot/test/compiler/stable/TestStableBoolean.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableBoolean { diff --git a/hotspot/test/compiler/stable/TestStableByte.java b/hotspot/test/compiler/stable/TestStableByte.java index 9201cd09794..694205e8e55 100644 --- a/hotspot/test/compiler/stable/TestStableByte.java +++ b/hotspot/test/compiler/stable/TestStableByte.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableByte { diff --git a/hotspot/test/compiler/stable/TestStableChar.java b/hotspot/test/compiler/stable/TestStableChar.java index f1a2e9f5842..d92dfb67c73 100644 --- a/hotspot/test/compiler/stable/TestStableChar.java +++ b/hotspot/test/compiler/stable/TestStableChar.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableChar { diff --git a/hotspot/test/compiler/stable/TestStableDouble.java b/hotspot/test/compiler/stable/TestStableDouble.java index 54ff453cd66..5e55a0f8597 100644 --- a/hotspot/test/compiler/stable/TestStableDouble.java +++ b/hotspot/test/compiler/stable/TestStableDouble.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableDouble { diff --git a/hotspot/test/compiler/stable/TestStableFloat.java b/hotspot/test/compiler/stable/TestStableFloat.java index 00a90591092..04acead22ef 100644 --- a/hotspot/test/compiler/stable/TestStableFloat.java +++ b/hotspot/test/compiler/stable/TestStableFloat.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableFloat { diff --git a/hotspot/test/compiler/stable/TestStableInt.java b/hotspot/test/compiler/stable/TestStableInt.java index 5a052a15dec..2837bd3d1a5 100644 --- a/hotspot/test/compiler/stable/TestStableInt.java +++ b/hotspot/test/compiler/stable/TestStableInt.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableInt { diff --git a/hotspot/test/compiler/stable/TestStableLong.java b/hotspot/test/compiler/stable/TestStableLong.java index a859a6b20d7..b6c2fbb0be6 100644 --- a/hotspot/test/compiler/stable/TestStableLong.java +++ b/hotspot/test/compiler/stable/TestStableLong.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableLong { diff --git a/hotspot/test/compiler/stable/TestStableMemoryBarrier.java b/hotspot/test/compiler/stable/TestStableMemoryBarrier.java index 6a1e1f6d149..4d3a223463c 100644 --- a/hotspot/test/compiler/stable/TestStableMemoryBarrier.java +++ b/hotspot/test/compiler/stable/TestStableMemoryBarrier.java @@ -36,6 +36,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableMemoryBarrier { diff --git a/hotspot/test/compiler/stable/TestStableObject.java b/hotspot/test/compiler/stable/TestStableObject.java index 38b8c1ce9df..b61736b6e32 100644 --- a/hotspot/test/compiler/stable/TestStableObject.java +++ b/hotspot/test/compiler/stable/TestStableObject.java @@ -83,6 +83,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableObject { diff --git a/hotspot/test/compiler/stable/TestStableShort.java b/hotspot/test/compiler/stable/TestStableShort.java index 57e52cfa0d4..1b0f127785c 100644 --- a/hotspot/test/compiler/stable/TestStableShort.java +++ b/hotspot/test/compiler/stable/TestStableShort.java @@ -82,6 +82,8 @@ */ package java.lang.invoke; +import jdk.internal.vm.annotation.Stable; + import java.lang.reflect.InvocationTargetException; public class TestStableShort { diff --git a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java index bd2b28db674..8c144143d62 100644 --- a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java +++ b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java @@ -40,10 +40,16 @@ */ package java.lang.invoke; -import jdk.internal.org.objectweb.asm.*; -import jdk.test.lib.Asserts; -import jdk.test.lib.Utils; +import jdk.internal.vm.annotation.DontInline; +import jdk.internal.vm.annotation.Stable; import jdk.internal.misc.Unsafe; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.Type; +import jdk.test.lib.Asserts; + import static jdk.internal.org.objectweb.asm.Opcodes.*; public class UnsafeGetConstantField { From e469a43b3e5a9916af1be5630237a4d014c9c4b5 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Thu, 3 Dec 2015 12:00:37 +0100 Subject: [PATCH 018/215] 8141526: Allow to collect stdout/stderr from the FinalizationRunner even before the process returns Reviewed-by: dsamersoff --- .../share/classes/jdk/test/lib/Asserts.java | 620 +++++++++++++++++ .../classes/jdk/test/lib/JDKToolFinder.java | 106 +++ .../classes/jdk/test/lib/JDKToolLauncher.java | 135 ++++ .../share/classes/jdk/test/lib/Platform.java | 206 ++++++ .../lib/share/classes/jdk/test/lib/Utils.java | 640 ++++++++++++++++++ .../jdk/test/lib/process/OutputAnalyzer.java | 436 ++++++++++++ .../jdk/test/lib/process/OutputBuffer.java | 59 ++ .../jdk/test/lib/process/ProcessTools.java | 590 ++++++++++++++++ .../jdk/test/lib/process/StreamPumper.java | 197 ++++++ 9 files changed, 2989 insertions(+) create mode 100644 test/lib/share/classes/jdk/test/lib/Asserts.java create mode 100644 test/lib/share/classes/jdk/test/lib/JDKToolFinder.java create mode 100644 test/lib/share/classes/jdk/test/lib/JDKToolLauncher.java create mode 100644 test/lib/share/classes/jdk/test/lib/Platform.java create mode 100644 test/lib/share/classes/jdk/test/lib/Utils.java create mode 100644 test/lib/share/classes/jdk/test/lib/process/OutputAnalyzer.java create mode 100644 test/lib/share/classes/jdk/test/lib/process/OutputBuffer.java create mode 100644 test/lib/share/classes/jdk/test/lib/process/ProcessTools.java create mode 100644 test/lib/share/classes/jdk/test/lib/process/StreamPumper.java diff --git a/test/lib/share/classes/jdk/test/lib/Asserts.java b/test/lib/share/classes/jdk/test/lib/Asserts.java new file mode 100644 index 00000000000..f0be92ef331 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/Asserts.java @@ -0,0 +1,620 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.test.lib; + +import java.util.Objects; + +/** + * Asserts that can be used for verifying assumptions in tests. + * + * An assertion will throw a {@link RuntimeException} if the assertion isn't true. + * All the asserts can be imported into a test by using a static import: + * + *
+ * {@code
+ * import static jdk.testlibrary.Asserts.*;
+ * }
+ *
+ * Always provide a message describing the assumption if the line number of the
+ * failing assertion isn't enough to understand why the assumption failed. For
+ * example, if the assertion is in a loop or in a method that is called
+ * multiple times, then the line number won't provide enough context to
+ * understand the failure.
+ * 
+ */ +public class Asserts { + + /** + * Shorthand for {@link #assertLessThan(Comparable, Comparable)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertLessThan(Comparable, Comparable) + */ + public static > void assertLT(T lhs, T rhs) { + assertLessThan(lhs, rhs); + } + + /** + * Shorthand for {@link #assertLessThan(Comparable, Comparable, String)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertLessThan(Comparable, Comparable, String) + */ + public static > void assertLT(T lhs, T rhs, String msg) { + assertLessThan(lhs, rhs, msg); + } + + /** + * Calls {@link #assertLessThan(Comparable, Comparable, String)} with a default message. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertLessThan(Comparable, Comparable, String) + */ + public static > void assertLessThan(T lhs, T rhs) { + assertLessThan(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is less than {@code rhs}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static >void assertLessThan(T lhs, T rhs, String msg) { + if (!(compare(lhs, rhs, msg) < 0)) { + msg = Objects.toString(msg, "assertLessThan") + + ": expected that " + Objects.toString(lhs) + + " < " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertLessThanOrEqual(Comparable, Comparable)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertLessThanOrEqual(Comparable, Comparable) + */ + public static > void assertLTE(T lhs, T rhs) { + assertLessThanOrEqual(lhs, rhs); + } + + /** + * Shorthand for {@link #assertLessThanOrEqual(Comparable, Comparable, String)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertLessThanOrEqual(Comparable, Comparable, String) + */ + public static > void assertLTE(T lhs, T rhs, String msg) { + assertLessThanOrEqual(lhs, rhs, msg); + } + + /** + * Calls {@link #assertLessThanOrEqual(Comparable, Comparable, String)} with a default message. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertLessThanOrEqual(Comparable, Comparable, String) + */ + public static > void assertLessThanOrEqual(T lhs, T rhs) { + assertLessThanOrEqual(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is less than or equal to {@code rhs}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static > void assertLessThanOrEqual(T lhs, T rhs, String msg) { + if (!(compare(lhs, rhs, msg) <= 0)) { + msg = Objects.toString(msg, "assertLessThanOrEqual") + + ": expected that " + Objects.toString(lhs) + + " <= " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertEquals(Object, Object)}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertEquals(Object, Object) + */ + public static void assertEQ(Object lhs, Object rhs) { + assertEquals(lhs, rhs); + } + + /** + * Shorthand for {@link #assertEquals(Object, Object, String)}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertEquals(Object, Object, String) + */ + public static void assertEQ(Object lhs, Object rhs, String msg) { + assertEquals(lhs, rhs, msg); + } + + /** + * Calls {@link #assertEquals(java.lang.Object, java.lang.Object, java.lang.String)} with a default message. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertEquals(Object, Object, String) + */ + public static void assertEquals(Object lhs, Object rhs) { + assertEquals(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertEquals(Object lhs, Object rhs, String msg) { + if ((lhs != rhs) && ((lhs == null) || !(lhs.equals(rhs)))) { + msg = Objects.toString(msg, "assertEquals") + + ": expected " + Objects.toString(lhs) + + " to equal " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Calls {@link #assertSame(java.lang.Object, java.lang.Object, java.lang.String)} with a default message. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertSame(Object, Object, String) + */ + public static void assertSame(Object lhs, Object rhs) { + assertSame(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is the same as {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertSame(Object lhs, Object rhs, String msg) { + if (lhs != rhs) { + msg = Objects.toString(msg, "assertSame") + + ": expected " + Objects.toString(lhs) + + " to equal " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertGreaterThanOrEqual(Comparable, Comparable)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertGreaterThanOrEqual(Comparable, Comparable) + */ + public static > void assertGTE(T lhs, T rhs) { + assertGreaterThanOrEqual(lhs, rhs); + } + + /** + * Shorthand for {@link #assertGreaterThanOrEqual(Comparable, Comparable, String)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertGreaterThanOrEqual(Comparable, Comparable, String) + */ + public static > void assertGTE(T lhs, T rhs, String msg) { + assertGreaterThanOrEqual(lhs, rhs, msg); + } + + /** + * Calls {@link #assertGreaterThanOrEqual(Comparable, Comparable, String)} with a default message. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertGreaterThanOrEqual(Comparable, Comparable, String) + */ + public static > void assertGreaterThanOrEqual(T lhs, T rhs) { + assertGreaterThanOrEqual(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is greater than or equal to {@code rhs}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static > void assertGreaterThanOrEqual(T lhs, T rhs, String msg) { + if (!(compare(lhs, rhs, msg) >= 0)) { + msg = Objects.toString(msg, "assertGreaterThanOrEqual") + + ": expected " + Objects.toString(lhs) + + " >= " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertGreaterThan(Comparable, Comparable)}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertGreaterThan(Comparable, Comparable) + */ + public static > void assertGT(T lhs, T rhs) { + assertGreaterThan(lhs, rhs); + } + + /** + * Shorthand for {@link #assertGreaterThan(Comparable, Comparable, String)}. + * + * @param a type + * @param lhs the left hand value + * @param rhs the right hand value + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertGreaterThan(Comparable, Comparable, String) + */ + public static > void assertGT(T lhs, T rhs, String msg) { + assertGreaterThan(lhs, rhs, msg); + } + + /** + * Calls {@link #assertGreaterThan(Comparable, Comparable, String)} with a default message. + * + * @param a type + * @param lhs the left hand value + * @param rhs the right hand value + * @see #assertGreaterThan(Comparable, Comparable, String) + */ + public static > void assertGreaterThan(T lhs, T rhs) { + assertGreaterThan(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is greater than {@code rhs}. + * + * @param a type + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static > void assertGreaterThan(T lhs, T rhs, String msg) { + if (!(compare(lhs, rhs, msg) > 0)) { + msg = Objects.toString(msg, "assertGreaterThan") + + ": expected " + Objects.toString(lhs) + + " > " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Shorthand for {@link #assertNotEquals(Object, Object)}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertNotEquals(Object, Object) + */ + public static void assertNE(Object lhs, Object rhs) { + assertNotEquals(lhs, rhs); + } + + /** + * Shorthand for {@link #assertNotEquals(Object, Object, String)}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @see #assertNotEquals(Object, Object, String) + */ + public static void assertNE(Object lhs, Object rhs, String msg) { + assertNotEquals(lhs, rhs, msg); + } + + /** + * Calls {@link #assertNotEquals(Object, Object, String)} with a default message. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @see #assertNotEquals(Object, Object, String) + */ + public static void assertNotEquals(Object lhs, Object rhs) { + assertNotEquals(lhs, rhs, null); + } + + /** + * Asserts that {@code lhs} is not equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertNotEquals(Object lhs, Object rhs, String msg) { + if ((lhs == rhs) || (lhs != null && lhs.equals(rhs))) { + msg = Objects.toString(msg, "assertNotEquals") + + ": expected " + Objects.toString(lhs) + + " to not equal " + Objects.toString(rhs); + fail(msg); + } + } + + /** + * Calls {@link #assertNull(Object, String)} with a default message. + * + * @param o The reference assumed to be null. + * @see #assertNull(Object, String) + */ + public static void assertNull(Object o) { + assertNull(o, null); + } + + /** + * Asserts that {@code o} is null. + * + * @param o The reference assumed to be null. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertNull(Object o, String msg) { + assertEquals(o, null, msg); + } + + /** + * Calls {@link #assertNotNull(Object, String)} with a default message. + * + * @param o The reference assumed not to be null, + * @see #assertNotNull(Object, String) + */ + public static void assertNotNull(Object o) { + assertNotNull(o, null); + } + + /** + * Asserts that {@code o} is not null. + * + * @param o The reference assumed not to be null, + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertNotNull(Object o, String msg) { + assertNotEquals(o, null, msg); + } + + /** + * Calls {@link #assertFalse(boolean, String)} with a default message. + * + * @param value The value assumed to be false. + * @see #assertFalse(boolean, String) + */ + public static void assertFalse(boolean value) { + assertFalse(value, null); + } + + /** + * Asserts that {@code value} is {@code false}. + * + * @param value The value assumed to be false. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertFalse(boolean value, String msg) { + if (value) { + msg = Objects.toString(msg, "assertFalse") + + ": expected false, was true"; + fail(msg); + } + } + + /** + * Calls {@link #assertTrue(boolean, String)} with a default message. + * + * @param value The value assumed to be true. + * @see #assertTrue(boolean, String) + */ + public static void assertTrue(boolean value) { + assertTrue(value, null); + } + + /** + * Asserts that {@code value} is {@code true}. + * + * @param value The value assumed to be true. + * @param msg A description of the assumption; {@code null} for a default message. + * @throws RuntimeException if the assertion is not true. + */ + public static void assertTrue(boolean value, String msg) { + if (!value) { + msg = Objects.toString(msg, "assertTrue") + + ": expected true, was false"; + fail(msg); + } + } + + private static > int compare(T lhs, T rhs, String msg) { + if (lhs == null || rhs == null) { + fail(lhs, rhs, msg + ": values must be non-null:", ","); + } + return lhs.compareTo(rhs); + } + +/** + * Asserts that two strings are equal. + * + * If strings are not equals, then exception message + * will contain {@code msg} followed by list of mismatched lines. + * + * @param str1 First string to compare. + * @param str2 Second string to compare. + * @param msg A description of the assumption. + * @throws RuntimeException if strings are not equal. + */ + public static void assertStringsEqual(String str1, String str2, + String msg) { + String lineSeparator = System.getProperty("line.separator"); + String str1Lines[] = str1.split(lineSeparator); + String str2Lines[] = str2.split(lineSeparator); + + int minLength = Math.min(str1Lines.length, str2Lines.length); + String longestStringLines[] = ((str1Lines.length == minLength) ? + str2Lines : str1Lines); + + boolean stringsAreDifferent = false; + + StringBuilder messageBuilder = new StringBuilder(msg); + + messageBuilder.append("\n"); + + for (int line = 0; line < minLength; line++) { + if (!str1Lines[line].equals(str2Lines[line])) { + messageBuilder.append(String. + format("[line %d] '%s' differs " + + "from '%s'\n", + line, + str1Lines[line], + str2Lines[line])); + stringsAreDifferent = true; + } + } + + if (minLength < longestStringLines.length) { + String stringName = ((longestStringLines == str1Lines) ? + "first" : "second"); + messageBuilder.append(String.format("Only %s string contains " + + "following lines:\n", + stringName)); + stringsAreDifferent = true; + for(int line = minLength; line < longestStringLines.length; line++) { + messageBuilder.append(String. + format("[line %d] '%s'", line, + longestStringLines[line])); + } + } + + if (stringsAreDifferent) { + fail(messageBuilder.toString()); + } + } + + /** + * Returns a string formatted with a message and expected and actual values. + * @param lhs the actual value + * @param rhs the expected value + * @param message the actual value + * @param relation the asserted relationship between lhs and rhs + * @return a formatted string + */ + public static String format(Object lhs, Object rhs, String message, String relation) { + StringBuilder sb = new StringBuilder(80); + if (message != null) { + sb.append(message); + sb.append(' '); + } + sb.append("<"); + sb.append(Objects.toString(lhs)); + sb.append("> "); + sb.append(Objects.toString(relation, ",")); + sb.append(" <"); + sb.append(Objects.toString(rhs)); + sb.append(">"); + return sb.toString(); + } + + /** + * Fail reports a failure with message fail. + * + * @throws RuntimeException always + */ + public static void fail() { + fail("fail"); + } + + /** + * Fail reports a failure with a message. + * @param message for the failure + * @throws RuntimeException always + */ + public static void fail(String message) { + throw new RuntimeException(message); + } + + /** + * Fail reports a failure with a formatted message. + * + * @param lhs the actual value + * @param rhs the expected value + * @param message to be format before the expected and actual values + * @param relation the asserted relationship between lhs and rhs + * @throws RuntimeException always + */ + public static void fail(Object lhs, Object rhs, String message, String relation) { + throw new RuntimeException(format(lhs, rhs, message, relation)); + } + + /** + * Fail reports a failure with a message and a cause. + * @param message to be format before the expected and actual values + * @param cause the exception that caused this failure + * @throws RuntimeException always + */ + public static void fail(String message, Throwable cause) { + throw new RuntimeException(message, cause); + } + +} diff --git a/test/lib/share/classes/jdk/test/lib/JDKToolFinder.java b/test/lib/share/classes/jdk/test/lib/JDKToolFinder.java new file mode 100644 index 00000000000..3ad008e0005 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/JDKToolFinder.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.test.lib; + +import java.io.FileNotFoundException; +import java.nio.file.Path; +import java.nio.file.Paths; + +public final class JDKToolFinder { + + private JDKToolFinder() { + } + + /** + * Returns the full path to an executable in jdk/bin based on System + * property {@code test.jdk} or {@code compile.jdk} (both are set by the jtreg test suite) + * + * @return Full path to an executable in jdk/bin + */ + public static String getJDKTool(String tool) { + + // First try to find the executable in test.jdk + try { + return getTool(tool, "test.jdk"); + } catch (FileNotFoundException e) { + + } + + // Now see if it's available in compile.jdk + try { + return getTool(tool, "compile.jdk"); + } catch (FileNotFoundException e) { + throw new RuntimeException("Failed to find " + tool + + ", looked in test.jdk (" + System.getProperty("test.jdk") + + ") and compile.jdk (" + System.getProperty("compile.jdk") + ")"); + } + } + + /** + * Returns the full path to an executable in jdk/bin based on System + * property {@code compile.jdk} + * + * @return Full path to an executable in jdk/bin + */ + public static String getCompileJDKTool(String tool) { + try { + return getTool(tool, "compile.jdk"); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + + /** + * Returns the full path to an executable in jdk/bin based on System + * property {@code test.jdk} + * + * @return Full path to an executable in jdk/bin + */ + public static String getTestJDKTool(String tool) { + try { + return getTool(tool, "test.jdk"); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + + private static String getTool(String tool, String property) throws FileNotFoundException { + String jdkPath = System.getProperty(property); + + if (jdkPath == null) { + throw new RuntimeException( + "System property '" + property + "' not set. This property is normally set by jtreg. " + + "When running test separately, set this property using '-D" + property + "=/path/to/jdk'."); + } + + Path toolName = Paths.get("bin", tool + (Platform.isWindows() ? ".exe" : "")); + + Path jdkTool = Paths.get(jdkPath, toolName.toString()); + if (!jdkTool.toFile().exists()) { + throw new FileNotFoundException("Could not find file " + jdkTool.toAbsolutePath()); + } + + return jdkTool.toAbsolutePath().toString(); + } +} diff --git a/test/lib/share/classes/jdk/test/lib/JDKToolLauncher.java b/test/lib/share/classes/jdk/test/lib/JDKToolLauncher.java new file mode 100644 index 00000000000..3948d474ec1 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/JDKToolLauncher.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.test.lib; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import jdk.test.lib.process.*; + +/** + * A utility for constructing command lines for starting JDK tool processes. + * + * The JDKToolLauncher can in particular be combined with a + * java.lang.ProcessBuilder to easily run a JDK tool. For example, the following + * code run {@code jmap -heap} against a process with GC logging turned on for + * the {@code jmap} process: + * + *
+ * {@code
+ * JDKToolLauncher jmap = JDKToolLauncher.create("jmap")
+ *                                       .addVMArg("-XX:+PrintGC");
+ *                                       .addVMArg("-XX:+PrintGCDetails")
+ *                                       .addToolArg("-heap")
+ *                                       .addToolArg(pid);
+ * ProcessBuilder pb = new ProcessBuilder(jmap.getCommand());
+ * Process p = pb.start();
+ * }
+ * 
+ */ +public class JDKToolLauncher { + private final String executable; + private final List vmArgs = new ArrayList(); + private final List toolArgs = new ArrayList(); + + private JDKToolLauncher(String tool, boolean useCompilerJDK) { + if (useCompilerJDK) { + executable = JDKToolFinder.getJDKTool(tool); + } else { + executable = JDKToolFinder.getTestJDKTool(tool); + } + vmArgs.addAll(Arrays.asList(ProcessTools.getPlatformSpecificVMArgs())); + } + + /** + * Creates a new JDKToolLauncher for the specified tool. Using tools path + * from the compiler JDK. + * + * @param tool + * The name of the tool + * @return A new JDKToolLauncher + */ + public static JDKToolLauncher create(String tool) { + return new JDKToolLauncher(tool, true); + } + + /** + * Creates a new JDKToolLauncher for the specified tool in the Tested JDK. + * + * @param tool + * The name of the tool + * + * @return A new JDKToolLauncher + */ + public static JDKToolLauncher createUsingTestJDK(String tool) { + return new JDKToolLauncher(tool, false); + } + + /** + * Adds an argument to the JVM running the tool. + * + * The JVM arguments are passed to the underlying JVM running the tool. + * Arguments will automatically be prepended with "-J". + * + * Any platform specific arguments required for running the tool are + * automatically added. + * + * + * @param arg + * The argument to VM running the tool + * @return The JDKToolLauncher instance + */ + public JDKToolLauncher addVMArg(String arg) { + vmArgs.add(arg); + return this; + } + + /** + * Adds an argument to the tool. + * + * @param arg + * The argument to the tool + * @return The JDKToolLauncher instance + */ + public JDKToolLauncher addToolArg(String arg) { + toolArgs.add(arg); + return this; + } + + /** + * Returns the command that can be used for running the tool. + * + * @return An array whose elements are the arguments of the command. + */ + public String[] getCommand() { + List command = new ArrayList(); + command.add(executable); + // Add -J in front of all vmArgs + for (String arg : vmArgs) { + command.add("-J" + arg); + } + command.addAll(toolArgs); + return command.toArray(new String[command.size()]); + } +} diff --git a/test/lib/share/classes/jdk/test/lib/Platform.java b/test/lib/share/classes/jdk/test/lib/Platform.java new file mode 100644 index 00000000000..f809d694312 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/Platform.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.test.lib; + +import java.util.regex.Pattern; + +public class Platform { + private static final String osName = System.getProperty("os.name"); + private static final String dataModel = System.getProperty("sun.arch.data.model"); + private static final String vmVersion = System.getProperty("java.vm.version"); + private static final String javaVersion = System.getProperty("java.version"); + private static final String osArch = System.getProperty("os.arch"); + private static final String vmName = System.getProperty("java.vm.name"); + private static final String userName = System.getProperty("user.name"); + private static final String compiler = System.getProperty("sun.management.compiler"); + + public static boolean isClient() { + return vmName.endsWith(" Client VM"); + } + + public static boolean isServer() { + return vmName.endsWith(" Server VM"); + } + + public static boolean isGraal() { + return vmName.endsWith(" Graal VM"); + } + + public static boolean isZero() { + return vmName.endsWith(" Zero VM"); + } + + public static boolean isMinimal() { + return vmName.endsWith(" Minimal VM"); + } + + public static boolean isEmbedded() { + return vmName.contains("Embedded"); + } + + public static boolean isTieredSupported() { + return compiler.contains("Tiered Compilers"); + } + + public static boolean is32bit() { + return dataModel.equals("32"); + } + + public static boolean is64bit() { + return dataModel.equals("64"); + } + + public static boolean isAix() { + return isOs("aix"); + } + + public static boolean isLinux() { + return isOs("linux"); + } + + public static boolean isOSX() { + return isOs("mac"); + } + + public static boolean isSolaris() { + return isOs("sunos"); + } + + public static boolean isWindows() { + return isOs("win"); + } + + private static boolean isOs(String osname) { + return osName.toLowerCase().startsWith(osname.toLowerCase()); + } + + public static String getOsName() { + return osName; + } + + public static boolean isDebugBuild() { + return (vmVersion.toLowerCase().contains("debug") || + javaVersion.toLowerCase().contains("debug")); + } + + public static String getVMVersion() { + return vmVersion; + } + + // Returns true for sparc and sparcv9. + public static boolean isSparc() { + return isArch("sparc.*"); + } + + public static boolean isARM() { + return isArch("arm.*"); + } + + public static boolean isPPC() { + return isArch("ppc.*"); + } + + public static boolean isX86() { + // On Linux it's 'i386', Windows 'x86' without '_64' suffix. + return isArch("(i386)|(x86(?!_64))"); + } + + public static boolean isX64() { + // On OSX it's 'x86_64' and on other (Linux, Windows and Solaris) platforms it's 'amd64' + return isArch("(amd64)|(x86_64)"); + } + + public static boolean isAArch64() { + return isArch("aarch64"); + } + + private static boolean isArch(String archnameRE) { + return Pattern.compile(archnameRE, Pattern.CASE_INSENSITIVE) + .matcher(osArch) + .matches(); + } + + public static String getOsArch() { + return osArch; + } + + /** + * Return a boolean for whether we expect to be able to attach + * the SA to our own processes on this system. + */ + public static boolean shouldSAAttach() throws Exception { + + if (isAix()) { + return false; // SA not implemented. + } else if (isLinux()) { + return canPtraceAttachLinux(); + } else if (isOSX()) { + return canAttachOSX(); + } else { + // Other platforms expected to work: + return true; + } + } + + /** + * On Linux, first check the SELinux boolean "deny_ptrace" and return false + * as we expect to be denied if that is "1". Then expect permission to attach + * if we are root, so return true. Then return false for an expected denial + * if "ptrace_scope" is 1, and true otherwise. + */ + public static boolean canPtraceAttachLinux() throws Exception { + + // SELinux deny_ptrace: + String deny_ptrace = Utils.fileAsString("/sys/fs/selinux/booleans/deny_ptrace"); + if (deny_ptrace != null && deny_ptrace.contains("1")) { + // ptrace will be denied: + return false; + } + + // YAMA enhanced security ptrace_scope: + // 0 - a process can PTRACE_ATTACH to any other process running under the same uid + // 1 - restricted ptrace: a process must be a children of the inferior or user is root + // 2 - only processes with CAP_SYS_PTRACE may use ptrace or user is root + // 3 - no attach: no processes may use ptrace with PTRACE_ATTACH + String ptrace_scope = Utils.fileAsString("/proc/sys/kernel/yama/ptrace_scope"); + if (ptrace_scope != null) { + if (ptrace_scope.startsWith("3")) { + return false; + } + if (!userName.equals("root") && !ptrace_scope.startsWith("0")) { + // ptrace will be denied: + return false; + } + } + // Otherwise expect to be permitted: + return true; + } + + /** + * On OSX, expect permission to attach only if we are root. + */ + public static boolean canAttachOSX() throws Exception { + return userName.equals("root"); + } +} diff --git a/test/lib/share/classes/jdk/test/lib/Utils.java b/test/lib/share/classes/jdk/test/lib/Utils.java new file mode 100644 index 00000000000..5634e088074 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/Utils.java @@ -0,0 +1,640 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.test.lib; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.ServerSocket; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.UnknownHostException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import java.util.function.BooleanSupplier; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import sun.misc.Unsafe; + +import jdk.test.lib.process.*; +import static jdk.test.lib.Asserts.assertTrue; + +/** + * Common library for various test helper functions. + */ +public final class Utils { + + /** + * Returns the value of 'test.class.path' system property. + */ + public static final String TEST_CLASS_PATH = System.getProperty("test.class.path", "."); + + /** + * Returns the sequence used by operating system to separate lines. + */ + public static final String NEW_LINE = System.getProperty("line.separator"); + + /** + * Returns the value of 'test.vm.opts' system property. + */ + public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim(); + + /** + * Returns the value of 'test.java.opts' system property. + */ + public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim(); + + /** + * Returns the value of 'test.src' system property. + */ + public static final String TEST_SRC = System.getProperty("test.src", "").trim(); + + private static Unsafe unsafe = null; + + /** + * Defines property name for seed value. + */ + public static final String SEED_PROPERTY_NAME = "jdk.test.lib.random.seed"; + + /* (non-javadoc) + * Random generator with (or without) predefined seed. Depends on + * "jdk.test.lib.random.seed" property value. + */ + private static volatile Random RANDOM_GENERATOR; + + /** + * Contains the seed value used for {@link java.util.Random} creation. + */ + public static final long SEED = Long.getLong(SEED_PROPERTY_NAME, new Random().nextLong()); + /** + * Returns the value of 'test.timeout.factor' system property + * converted to {@code double}. + */ + public static final double TIMEOUT_FACTOR; + static { + String toFactor = System.getProperty("test.timeout.factor", "1.0"); + TIMEOUT_FACTOR = Double.parseDouble(toFactor); + } + + /** + * Returns the value of JTREG default test timeout in milliseconds + * converted to {@code long}. + */ + public static final long DEFAULT_TEST_TIMEOUT = TimeUnit.SECONDS.toMillis(120); + + private Utils() { + // Private constructor to prevent class instantiation + } + + /** + * Returns the list of VM options. + * + * @return List of VM options + */ + public static List getVmOptions() { + return Arrays.asList(safeSplitString(VM_OPTIONS)); + } + + /** + * Returns the list of VM options with -J prefix. + * + * @return The list of VM options with -J prefix + */ + public static List getForwardVmOptions() { + String[] opts = safeSplitString(VM_OPTIONS); + for (int i = 0; i < opts.length; i++) { + opts[i] = "-J" + opts[i]; + } + return Arrays.asList(opts); + } + + /** + * Returns the default JTReg arguments for a jvm running a test. + * This is the combination of JTReg arguments test.vm.opts and test.java.opts. + * @return An array of options, or an empty array if no options. + */ + public static String[] getTestJavaOpts() { + List opts = new ArrayList(); + Collections.addAll(opts, safeSplitString(VM_OPTIONS)); + Collections.addAll(opts, safeSplitString(JAVA_OPTIONS)); + return opts.toArray(new String[0]); + } + + /** + * Combines given arguments with default JTReg arguments for a jvm running a test. + * This is the combination of JTReg arguments test.vm.opts and test.java.opts + * @return The combination of JTReg test java options and user args. + */ + public static String[] addTestJavaOpts(String... userArgs) { + List opts = new ArrayList(); + Collections.addAll(opts, getTestJavaOpts()); + Collections.addAll(opts, userArgs); + return opts.toArray(new String[0]); + } + + /** + * Removes any options specifying which GC to use, for example "-XX:+UseG1GC". + * Removes any options matching: -XX:(+/-)Use*GC + * Used when a test need to set its own GC version. Then any + * GC specified by the framework must first be removed. + * @return A copy of given opts with all GC options removed. + */ + private static final Pattern useGcPattern = Pattern.compile( + "(?:\\-XX\\:[\\+\\-]Use.+GC)" + + "|(?:\\-Xconcgc)"); + public static List removeGcOpts(List opts) { + List optsWithoutGC = new ArrayList(); + for (String opt : opts) { + if (useGcPattern.matcher(opt).matches()) { + System.out.println("removeGcOpts: removed " + opt); + } else { + optsWithoutGC.add(opt); + } + } + return optsWithoutGC; + } + + /** + * Returns the default JTReg arguments for a jvm running a test without + * options that matches regular expressions in {@code filters}. + * This is the combination of JTReg arguments test.vm.opts and test.java.opts. + * @param filters Regular expressions used to filter out options. + * @return An array of options, or an empty array if no options. + */ + public static String[] getFilteredTestJavaOpts(String... filters) { + String options[] = getTestJavaOpts(); + + if (filters.length == 0) { + return options; + } + + List filteredOptions = new ArrayList(options.length); + Pattern patterns[] = new Pattern[filters.length]; + for (int i = 0; i < filters.length; i++) { + patterns[i] = Pattern.compile(filters[i]); + } + + for (String option : options) { + boolean matched = false; + for (int i = 0; i < patterns.length && !matched; i++) { + Matcher matcher = patterns[i].matcher(option); + matched = matcher.find(); + } + if (!matched) { + filteredOptions.add(option); + } + } + + return filteredOptions.toArray(new String[filteredOptions.size()]); + } + + /** + * Splits a string by white space. + * Works like String.split(), but returns an empty array + * if the string is null or empty. + */ + private static String[] safeSplitString(String s) { + if (s == null || s.trim().isEmpty()) { + return new String[] {}; + } + return s.trim().split("\\s+"); + } + + /** + * @return The full command line for the ProcessBuilder. + */ + public static String getCommandLine(ProcessBuilder pb) { + StringBuilder cmd = new StringBuilder(); + for (String s : pb.command()) { + cmd.append(s).append(" "); + } + return cmd.toString(); + } + + /** + * Returns the free port on the local host. + * The function will spin until a valid port number is found. + * + * @return The port number + * @throws InterruptedException if any thread has interrupted the current thread + * @throws IOException if an I/O error occurs when opening the socket + */ + public static int getFreePort() throws InterruptedException, IOException { + int port = -1; + + while (port <= 0) { + Thread.sleep(100); + + ServerSocket serverSocket = null; + try { + serverSocket = new ServerSocket(0); + port = serverSocket.getLocalPort(); + } finally { + serverSocket.close(); + } + } + + return port; + } + + /** + * Returns the name of the local host. + * + * @return The host name + * @throws UnknownHostException if IP address of a host could not be determined + */ + public static String getHostname() throws UnknownHostException { + InetAddress inetAddress = InetAddress.getLocalHost(); + String hostName = inetAddress.getHostName(); + + assertTrue((hostName != null && !hostName.isEmpty()), + "Cannot get hostname"); + + return hostName; + } + + /** + * Uses "jcmd -l" to search for a jvm pid. This function will wait + * forever (until jtreg timeout) for the pid to be found. + * @param key Regular expression to search for + * @return The found pid. + */ + public static int waitForJvmPid(String key) throws Throwable { + final long iterationSleepMillis = 250; + System.out.println("waitForJvmPid: Waiting for key '" + key + "'"); + System.out.flush(); + while (true) { + int pid = tryFindJvmPid(key); + if (pid >= 0) { + return pid; + } + Thread.sleep(iterationSleepMillis); + } + } + + /** + * Searches for a jvm pid in the output from "jcmd -l". + * + * Example output from jcmd is: + * 12498 sun.tools.jcmd.JCmd -l + * 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar + * + * @param key A regular expression to search for. + * @return The found pid, or -1 if not found. + * @throws Exception If multiple matching jvms are found. + */ + public static int tryFindJvmPid(String key) throws Throwable { + OutputAnalyzer output = null; + try { + JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd"); + jcmdLauncher.addToolArg("-l"); + output = ProcessTools.executeProcess(jcmdLauncher.getCommand()); + output.shouldHaveExitValue(0); + + // Search for a line starting with numbers (pid), follwed by the key. + Pattern pattern = Pattern.compile("([0-9]+)\\s.*(" + key + ").*\\r?\\n"); + Matcher matcher = pattern.matcher(output.getStdout()); + + int pid = -1; + if (matcher.find()) { + pid = Integer.parseInt(matcher.group(1)); + System.out.println("findJvmPid.pid: " + pid); + if (matcher.find()) { + throw new Exception("Found multiple JVM pids for key: " + key); + } + } + return pid; + } catch (Throwable t) { + System.out.println(String.format("Utils.findJvmPid(%s) failed: %s", key, t)); + throw t; + } + } + + /** + * Adjusts the provided timeout value for the TIMEOUT_FACTOR + * @param tOut the timeout value to be adjusted + * @return The timeout value adjusted for the value of "test.timeout.factor" + * system property + */ + public static long adjustTimeout(long tOut) { + return Math.round(tOut * Utils.TIMEOUT_FACTOR); + } + + /** + * Return the contents of the named file as a single String, + * or null if not found. + * @param filename name of the file to read + * @return String contents of file, or null if file not found. + * @throws IOException + * if an I/O error occurs reading from the file or a malformed or + * unmappable byte sequence is read + */ + public static String fileAsString(String filename) throws IOException { + Path filePath = Paths.get(filename); + if (!Files.exists(filePath)) return null; + return new String(Files.readAllBytes(filePath)); + } + + /** + * @return Unsafe instance. + */ + public static synchronized Unsafe getUnsafe() { + if (unsafe == null) { + try { + Field f = Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + unsafe = (Unsafe) f.get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + } + return unsafe; + } + private static final char[] hexArray = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + /** + * Returns hex view of byte array + * + * @param bytes byte array to process + * @return Space separated hexadecimal string representation of bytes + */ + + public static String toHexString(byte[] bytes) { + char[] hexView = new char[bytes.length * 3]; + int i = 0; + for (byte b : bytes) { + hexView[i++] = hexArray[(b >> 4) & 0x0F]; + hexView[i++] = hexArray[b & 0x0F]; + hexView[i++] = ' '; + } + return new String(hexView); + } + + /** + * Returns {@link java.util.Random} generator initialized with particular seed. + * The seed could be provided via system property {@link Utils#SEED_PROPERTY_NAME} + * In case no seed is provided, the method uses a random number. + * The used seed printed to stdout. + * @return {@link java.util.Random} generator with particular seed. + */ + public static Random getRandomInstance() { + if (RANDOM_GENERATOR == null) { + synchronized (Utils.class) { + if (RANDOM_GENERATOR == null) { + RANDOM_GENERATOR = new Random(SEED); + System.out.printf("For random generator using seed: %d%n", SEED); + System.out.printf("To re-run test with same seed value please add \"-D%s=%d\" to command line.%n", SEED_PROPERTY_NAME, SEED); + } + } + } + return RANDOM_GENERATOR; + } + + /** + * Returns random element of non empty collection + * + * @param a type of collection element + * @param collection collection of elements + * @return random element of collection + * @throws IllegalArgumentException if collection is empty + */ + public static T getRandomElement(Collection collection) + throws IllegalArgumentException { + if (collection.isEmpty()) { + throw new IllegalArgumentException("Empty collection"); + } + Random random = getRandomInstance(); + int elementIndex = 1 + random.nextInt(collection.size() - 1); + Iterator iterator = collection.iterator(); + while (--elementIndex != 0) { + iterator.next(); + } + return iterator.next(); + } + + /** + * Wait for condition to be true + * + * @param condition, a condition to wait for + */ + public static final void waitForCondition(BooleanSupplier condition) { + waitForCondition(condition, -1L, 100L); + } + + /** + * Wait until timeout for condition to be true + * + * @param condition, a condition to wait for + * @param timeout a time in milliseconds to wait for condition to be true + * specifying -1 will wait forever + * @return condition value, to determine if wait was successful + */ + public static final boolean waitForCondition(BooleanSupplier condition, + long timeout) { + return waitForCondition(condition, timeout, 100L); + } + + /** + * Wait until timeout for condition to be true for specified time + * + * @param condition, a condition to wait for + * @param timeout a time in milliseconds to wait for condition to be true, + * specifying -1 will wait forever + * @param sleepTime a time to sleep value in milliseconds + * @return condition value, to determine if wait was successful + */ + public static final boolean waitForCondition(BooleanSupplier condition, + long timeout, long sleepTime) { + long startTime = System.currentTimeMillis(); + while (!(condition.getAsBoolean() || (timeout != -1L + && ((System.currentTimeMillis() - startTime) > timeout)))) { + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new Error(e); + } + } + return condition.getAsBoolean(); + } + + /** + * Interface same as java.lang.Runnable but with + * method {@code run()} able to throw any Throwable. + */ + public static interface ThrowingRunnable { + void run() throws Throwable; + } + + /** + * Filters out an exception that may be thrown by the given + * test according to the given filter. + * + * @param test - method that is invoked and checked for exception. + * @param filter - function that checks if the thrown exception matches + * criteria given in the filter's implementation. + * @return - exception that matches the filter if it has been thrown or + * {@code null} otherwise. + * @throws Throwable - if test has thrown an exception that does not + * match the filter. + */ + public static Throwable filterException(ThrowingRunnable test, + Function filter) throws Throwable { + try { + test.run(); + } catch (Throwable t) { + if (filter.apply(t)) { + return t; + } else { + throw t; + } + } + return null; + } + + /** + * Ensures a requested class is loaded + * @param aClass class to load + */ + public static void ensureClassIsLoaded(Class aClass) { + if (aClass == null) { + throw new Error("Requested null class"); + } + try { + Class.forName(aClass.getName(), /* initialize = */ true, + ClassLoader.getSystemClassLoader()); + } catch (ClassNotFoundException e) { + throw new Error("Class not found", e); + } + } + /** + * @param parent a class loader to be the parent for the returned one + * @return an UrlClassLoader with urls made of the 'test.class.path' jtreg + * property and with the given parent + */ + public static URLClassLoader getTestClassPathURLClassLoader(ClassLoader parent) { + URL[] urls = Arrays.stream(TEST_CLASS_PATH.split(File.pathSeparator)) + .map(Paths::get) + .map(Path::toUri) + .map(x -> { + try { + return x.toURL(); + } catch (MalformedURLException ex) { + throw new Error("Test issue. JTREG property" + + " 'test.class.path'" + + " is not defined correctly", ex); + } + }).toArray(URL[]::new); + return new URLClassLoader(urls, parent); + } + + /** + * Runs runnable and checks that it throws expected exception. If exceptionException is null it means + * that we expect no exception to be thrown. + * @param runnable what we run + * @param expectedException expected exception + */ + public static void runAndCheckException(Runnable runnable, Class expectedException) { + runAndCheckException(runnable, t -> { + if (t == null) { + if (expectedException != null) { + throw new AssertionError("Didn't get expected exception " + expectedException.getSimpleName()); + } + } else { + String message = "Got unexpected exception " + t.getClass().getSimpleName(); + if (expectedException == null) { + throw new AssertionError(message, t); + } else if (!expectedException.isAssignableFrom(t.getClass())) { + message += " instead of " + expectedException.getSimpleName(); + throw new AssertionError(message, t); + } + } + }); + } + + /** + * Runs runnable and makes some checks to ensure that it throws expected exception. + * @param runnable what we run + * @param checkException a consumer which checks that we got expected exception and raises a new exception otherwise + */ + public static void runAndCheckException(Runnable runnable, Consumer checkException) { + try { + runnable.run(); + checkException.accept(null); + } catch (Throwable t) { + checkException.accept(t); + } + } + + /** + * Converts to VM type signature + * + * @param type Java type to convert + * @return string representation of VM type + */ + public static String toJVMTypeSignature(Class type) { + if (type.isPrimitive()) { + if (type == boolean.class) { + return "Z"; + } else if (type == byte.class) { + return "B"; + } else if (type == char.class) { + return "C"; + } else if (type == double.class) { + return "D"; + } else if (type == float.class) { + return "F"; + } else if (type == int.class) { + return "I"; + } else if (type == long.class) { + return "J"; + } else if (type == short.class) { + return "S"; + } else if (type == void.class) { + return "V"; + } else { + throw new Error("Unsupported type: " + type); + } + } + String result = type.getName().replaceAll("\\.", "/"); + if (!type.isArray()) { + return "L" + result + ";"; + } + return result; + } +} + diff --git a/test/lib/share/classes/jdk/test/lib/process/OutputAnalyzer.java b/test/lib/share/classes/jdk/test/lib/process/OutputAnalyzer.java new file mode 100644 index 00000000000..fc3a4de2905 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/process/OutputAnalyzer.java @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.test.lib.process; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class OutputAnalyzer { + + private final String stdout; + private final String stderr; + private final int exitValue; + + /** + * Create an OutputAnalyzer, a utility class for verifying output and exit + * value from a Process + * + * @param process Process to analyze + * @throws IOException If an I/O error occurs. + */ + public OutputAnalyzer(Process process) throws IOException { + OutputBuffer output = ProcessTools.getOutput(process); + exitValue = process.exitValue(); + this.stdout = output.getStdout(); + this.stderr = output.getStderr(); + } + + /** + * Create an OutputAnalyzer, a utility class for verifying output + * + * @param buf String buffer to analyze + */ + public OutputAnalyzer(String buf) { + this(buf, buf); + } + + /** + * Create an OutputAnalyzer, a utility class for verifying output + * + * @param stdout stdout buffer to analyze + * @param stderr stderr buffer to analyze + */ + public OutputAnalyzer(String stdout, String stderr) { + this.stdout = stdout; + this.stderr = stderr; + exitValue = -1; + } + + /** + * Verify that the stdout contents of output buffer is empty + * + * @throws RuntimeException + * If stdout was not empty + */ + public void stdoutShouldBeEmpty() { + if (!getStdout().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stdout was not empty"); + } + } + + /** + * Verify that the stderr contents of output buffer is empty + * + * @throws RuntimeException + * If stderr was not empty + */ + public void stderrShouldBeEmpty() { + if (!getStderr().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stderr was not empty"); + } + } + + /** + * Verify that the stdout contents of output buffer is not empty + * + * @throws RuntimeException + * If stdout was empty + */ + public void stdoutShouldNotBeEmpty() { + if (getStdout().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stdout was empty"); + } + } + + /** + * Verify that the stderr contents of output buffer is not empty + * + * @throws RuntimeException + * If stderr was empty + */ + public void stderrShouldNotBeEmpty() { + if (getStderr().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stderr was empty"); + } + } + + /** + * Verify that the stdout and stderr contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public OutputAnalyzer shouldContain(String expectedString) { + if (!stdout.contains(expectedString) && !stderr.contains(expectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + expectedString + "' missing from stdout/stderr \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public OutputAnalyzer stdoutShouldContain(String expectedString) { + if (!stdout.contains(expectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + expectedString + "' missing from stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer contains the string + * + * @param expectedString String that buffer should contain + * @throws RuntimeException If the string was not found + */ + public OutputAnalyzer stderrShouldContain(String expectedString) { + if (!stderr.contains(expectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + expectedString + "' missing from stderr \n"); + } + return this; + } + + /** + * Verify that the stdout and stderr contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public OutputAnalyzer shouldNotContain(String notExpectedString) { + if (stdout.contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + "' found in stdout \n"); + } + if (stderr.contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + "' found in stderr \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public OutputAnalyzer stdoutShouldNotContain(String notExpectedString) { + if (stdout.contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + "' found in stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer does not contain the string + * + * @param expectedString String that the buffer should not contain + * @throws RuntimeException If the string was found + */ + public OutputAnalyzer stderrShouldNotContain(String notExpectedString) { + if (stderr.contains(notExpectedString)) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + notExpectedString + "' found in stderr \n"); + } + return this; + } + + /** + * Verify that the stdout and stderr contents of output buffer matches + * the pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public OutputAnalyzer shouldMatch(String pattern) { + Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (!stdoutMatcher.find() && !stderrMatcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' missing from stdout/stderr \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer matches the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public OutputAnalyzer stdoutShouldMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (!matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' missing from stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer matches the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public OutputAnalyzer stderrShouldMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (!matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' missing from stderr \n"); + } + return this; + } + + /** + * Verify that the stdout and stderr contents of output buffer does not + * match the pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public OutputAnalyzer shouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' found in stdout: '" + matcher.group() + "' \n"); + } + matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' found in stderr: '" + matcher.group() + "' \n"); + } + return this; + } + + /** + * Verify that the stdout contents of output buffer does not match the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public OutputAnalyzer stdoutShouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' found in stdout \n"); + } + return this; + } + + /** + * Verify that the stderr contents of output buffer does not match the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public OutputAnalyzer stderrShouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (matcher.find()) { + reportDiagnosticSummary(); + throw new RuntimeException("'" + pattern + + "' found in stderr \n"); + } + return this; + } + + /** + * Get the captured group of the first string matching the pattern. + * stderr is searched before stdout. + * + * @param pattern The multi-line pattern to match + * @param group The group to capture + * @return The matched string or null if no match was found + */ + public String firstMatch(String pattern, int group) { + Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (stderrMatcher.find()) { + return stderrMatcher.group(group); + } + if (stdoutMatcher.find()) { + return stdoutMatcher.group(group); + } + return null; + } + + /** + * Get the first string matching the pattern. + * stderr is searched before stdout. + * + * @param pattern The multi-line pattern to match + * @return The matched string or null if no match was found + */ + public String firstMatch(String pattern) { + return firstMatch(pattern, 0); + } + + /** + * Verify the exit value of the process + * + * @param expectedExitValue Expected exit value from process + * @throws RuntimeException If the exit value from the process did not match the expected value + */ + public OutputAnalyzer shouldHaveExitValue(int expectedExitValue) { + if (getExitValue() != expectedExitValue) { + reportDiagnosticSummary(); + throw new RuntimeException("Expected to get exit value of [" + + expectedExitValue + "]\n"); + } + return this; + } + + + /** + * Report summary that will help to diagnose the problem + * Currently includes: + * - standard input produced by the process under test + * - standard output + * - exit code + * Note: the command line is printed by the ProcessTools + */ + private void reportDiagnosticSummary() { + String msg = + " stdout: [" + stdout + "];\n" + + " stderr: [" + stderr + "]\n" + + " exitValue = " + getExitValue() + "\n"; + + System.err.println(msg); + } + + + /** + * Get the contents of the output buffer (stdout and stderr) + * + * @return Content of the output buffer + */ + public String getOutput() { + return stdout + stderr; + } + + /** + * Get the contents of the stdout buffer + * + * @return Content of the stdout buffer + */ + public String getStdout() { + return stdout; + } + + /** + * Get the contents of the stderr buffer + * + * @return Content of the stderr buffer + */ + public String getStderr() { + return stderr; + } + + /** + * Get the process exit value + * + * @return Process exit value + */ + public int getExitValue() { + return exitValue; + } + + /** + * Get the contents of the output buffer (stdout and stderr) as list of strings. + * Output will be split by newlines. + * + * @return Contents of the output buffer as list of strings + */ + public List asLines() { + return asLines(getOutput()); + } + + private List asLines(String buffer) { + return Arrays.asList(buffer.split("(\\r\\n|\\n|\\r)")); + } +} diff --git a/test/lib/share/classes/jdk/test/lib/process/OutputBuffer.java b/test/lib/share/classes/jdk/test/lib/process/OutputBuffer.java new file mode 100644 index 00000000000..23976d8272f --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/process/OutputBuffer.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.test.lib.process; + +public class OutputBuffer { + private final String stdout; + private final String stderr; + + /** + * Create an OutputBuffer, a class for storing and managing stdout and stderr + * results separately + * + * @param stdout stdout result + * @param stderr stderr result + */ + public OutputBuffer(String stdout, String stderr) { + this.stdout = stdout; + this.stderr = stderr; + } + + /** + * Returns the stdout result + * + * @return stdout result + */ + public String getStdout() { + return stdout; + } + + /** + * Returns the stderr result + * + * @return stderr result + */ + public String getStderr() { + return stderr; + } +} diff --git a/test/lib/share/classes/jdk/test/lib/process/ProcessTools.java b/test/lib/share/classes/jdk/test/lib/process/ProcessTools.java new file mode 100644 index 00000000000..3189a0fe277 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/process/ProcessTools.java @@ -0,0 +1,590 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.test.lib.process; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.concurrent.CountDownLatch; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Predicate; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import jdk.test.lib.JDKToolFinder; +import jdk.test.lib.Platform; +import jdk.test.lib.Utils; + +public final class ProcessTools { + private static final class LineForwarder extends StreamPumper.LinePump { + private final PrintStream ps; + private final String prefix; + LineForwarder(String prefix, PrintStream os) { + this.ps = os; + this.prefix = prefix; + } + @Override + protected void processLine(String line) { + ps.println("[" + prefix + "] " + line); + } + } + + private ProcessTools() { + } + + /** + * Pumps stdout and stderr from running the process into a String. + * + * @param processHandler ProcessHandler to run. + * @return Output from process. + * @throws IOException If an I/O error occurs. + */ + public static OutputBuffer getOutput(ProcessBuilder processBuilder) throws IOException { + return getOutput(processBuilder.start()); + } + + /** + * Pumps stdout and stderr the running process into a String. + * + * @param process Process to pump. + * @return Output from process. + * @throws IOException If an I/O error occurs. + */ + public static OutputBuffer getOutput(Process process) throws IOException { + ByteArrayOutputStream stderrBuffer = new ByteArrayOutputStream(); + ByteArrayOutputStream stdoutBuffer = new ByteArrayOutputStream(); + StreamPumper outPumper = new StreamPumper(process.getInputStream(), stdoutBuffer); + StreamPumper errPumper = new StreamPumper(process.getErrorStream(), stderrBuffer); + Thread outPumperThread = new Thread(outPumper); + Thread errPumperThread = new Thread(errPumper); + + outPumperThread.setDaemon(true); + errPumperThread.setDaemon(true); + + outPumperThread.start(); + errPumperThread.start(); + + try { + process.waitFor(); + outPumperThread.join(); + errPumperThread.join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return null; + } + + return new OutputBuffer(stdoutBuffer.toString(), stderrBuffer.toString()); + } + + /** + *

Starts a process from its builder.

+ * The default redirects of STDOUT and STDERR are started + * @param name The process name + * @param processBuilder The process builder + * @return Returns the initialized process + * @throws IOException + */ + public static Process startProcess(String name, + ProcessBuilder processBuilder) + throws IOException { + return startProcess(name, processBuilder, (Consumer)null); + } + + /** + *

Starts a process from its builder.

+ * The default redirects of STDOUT and STDERR are started + *

It is possible to monitor the in-streams via the provided {@code consumer} + * @param name The process name + * @param consumer {@linkplain Consumer} instance to process the in-streams + * @param processBuilder The process builder + * @return Returns the initialized process + * @throws IOException + */ + @SuppressWarnings("overloads") + public static Process startProcess(String name, + ProcessBuilder processBuilder, + Consumer consumer) + throws IOException { + try { + return startProcess(name, processBuilder, consumer, null, -1, TimeUnit.NANOSECONDS); + } catch (InterruptedException | TimeoutException e) { + // will never happen + throw new RuntimeException(e); + } + } + + /** + *

Starts a process from its builder.

+ * The default redirects of STDOUT and STDERR are started + *

+ * It is possible to wait for the process to get to a warmed-up state + * via {@linkplain Predicate} condition on the STDOUT + *

+ * @param name The process name + * @param processBuilder The process builder + * @param linePredicate The {@linkplain Predicate} to use on the STDOUT + * Used to determine the moment the target app is + * properly warmed-up. + * It can be null - in that case the warmup is skipped. + * @param timeout The timeout for the warmup waiting; -1 = no wait; 0 = wait forever + * @param unit The timeout {@linkplain TimeUnit} + * @return Returns the initialized {@linkplain Process} + * @throws IOException + * @throws InterruptedException + * @throws TimeoutException + */ + public static Process startProcess(String name, + ProcessBuilder processBuilder, + final Predicate linePredicate, + long timeout, + TimeUnit unit) + throws IOException, InterruptedException, TimeoutException { + return startProcess(name, processBuilder, null, linePredicate, timeout, unit); + } + + /** + *

Starts a process from its builder.

+ * The default redirects of STDOUT and STDERR are started + *

+ * It is possible to wait for the process to get to a warmed-up state + * via {@linkplain Predicate} condition on the STDOUT and monitor the + * in-streams via the provided {@linkplain Consumer} + *

+ * @param name The process name + * @param processBuilder The process builder + * @param lineConsumer The {@linkplain Consumer} the lines will be forwarded to + * @param linePredicate The {@linkplain Predicate} to use on the STDOUT + * Used to determine the moment the target app is + * properly warmed-up. + * It can be null - in that case the warmup is skipped. + * @param timeout The timeout for the warmup waiting; -1 = no wait; 0 = wait forever + * @param unit The timeout {@linkplain TimeUnit} + * @return Returns the initialized {@linkplain Process} + * @throws IOException + * @throws InterruptedException + * @throws TimeoutException + */ + public static Process startProcess(String name, + ProcessBuilder processBuilder, + final Consumer lineConsumer, + final Predicate linePredicate, + long timeout, + TimeUnit unit) + throws IOException, InterruptedException, TimeoutException { + System.out.println("["+name+"]:" + processBuilder.command().stream().collect(Collectors.joining(" "))); + Process p = processBuilder.start(); + StreamPumper stdout = new StreamPumper(p.getInputStream()); + StreamPumper stderr = new StreamPumper(p.getErrorStream()); + + stdout.addPump(new LineForwarder(name, System.out)); + stderr.addPump(new LineForwarder(name, System.err)); + if (lineConsumer != null) { + StreamPumper.LinePump pump = new StreamPumper.LinePump() { + @Override + protected void processLine(String line) { + lineConsumer.accept(line); + } + }; + stdout.addPump(pump); + stderr.addPump(pump); + } + + + CountDownLatch latch = new CountDownLatch(1); + if (linePredicate != null) { + StreamPumper.LinePump pump = new StreamPumper.LinePump() { + @Override + protected void processLine(String line) { + if (latch.getCount() > 0 && linePredicate.test(line)) { + latch.countDown(); + } + } + }; + stdout.addPump(pump); + stderr.addPump(pump); + } else { + latch.countDown(); + } + final Future stdoutTask = stdout.process(); + final Future stderrTask = stderr.process(); + + try { + if (timeout > -1) { + if (timeout == 0) { + latch.await(); + } else { + if (!latch.await(Utils.adjustTimeout(timeout), unit)) { + throw new TimeoutException(); + } + } + } + } catch (TimeoutException | InterruptedException e) { + System.err.println("Failed to start a process (thread dump follows)"); + for(Map.Entry s : Thread.getAllStackTraces().entrySet()) { + printStack(s.getKey(), s.getValue()); + } + + if (p.isAlive()) { + p.destroyForcibly(); + } + + stdoutTask.cancel(true); + stderrTask.cancel(true); + throw e; + } + + return new ProcessImpl(p, stdoutTask, stderrTask); + } + + /** + *

Starts a process from its builder.

+ * The default redirects of STDOUT and STDERR are started + *

+ * It is possible to wait for the process to get to a warmed-up state + * via {@linkplain Predicate} condition on the STDOUT. The warm-up will + * wait indefinitely. + *

+ * @param name The process name + * @param processBuilder The process builder + * @param linePredicate The {@linkplain Predicate} to use on the STDOUT + * Used to determine the moment the target app is + * properly warmed-up. + * It can be null - in that case the warmup is skipped. + * @return Returns the initialized {@linkplain Process} + * @throws IOException + * @throws InterruptedException + * @throws TimeoutException + */ + @SuppressWarnings("overloads") + public static Process startProcess(String name, + ProcessBuilder processBuilder, + final Predicate linePredicate) + throws IOException, InterruptedException, TimeoutException { + return startProcess(name, processBuilder, linePredicate, 0, TimeUnit.SECONDS); + } + + /** + * Get the process id of the current running Java process + * + * @return Process id + */ + public static long getProcessId() throws Exception { + return ProcessHandle.current().getPid(); + } + + /** + * Get platform specific VM arguments (e.g. -d64 on 64bit Solaris) + * + * @return String[] with platform specific arguments, empty if there are + * none + */ + public static String[] getPlatformSpecificVMArgs() { + + if (Platform.is64bit() && Platform.isSolaris()) { + return new String[] { "-d64" }; + } + + return new String[] {}; + } + + + /** + * Create ProcessBuilder using the java launcher from the jdk to be tested and + * with any platform specific arguments prepended + */ + public static ProcessBuilder createJavaProcessBuilder(String... command) throws Exception { + return createJavaProcessBuilder(false, command); + } + + /** + * Create ProcessBuilder using the java launcher from the jdk to be tested, + * and with any platform specific arguments prepended. + * + * @param addTestVmAndJavaOptions If true, adds test.vm.opts and test.java.opts + * to the java arguments. + * @param command Arguments to pass to the java command. + * @return The ProcessBuilder instance representing the java command. + */ + public static ProcessBuilder createJavaProcessBuilder(boolean addTestVmAndJavaOptions, String... command) throws Exception { + String javapath = JDKToolFinder.getJDKTool("java"); + + ArrayList args = new ArrayList<>(); + args.add(javapath); + Collections.addAll(args, getPlatformSpecificVMArgs()); + + if (addTestVmAndJavaOptions) { + // -cp is needed to make sure the same classpath is used whether the test is + // run in AgentVM mode or OtherVM mode. It was added to the hotspot version + // of this API as part of 8077608. However, for the jdk version it is only + // added when addTestVmAndJavaOptions is true in order to minimize + // disruption to existing JDK tests, which have yet to be tested with -cp + // being added. At some point -cp should always be added to be consistent + // with what the hotspot version does. + args.add("-cp"); + args.add(System.getProperty("java.class.path")); + Collections.addAll(args, Utils.getTestJavaOpts()); + } + + Collections.addAll(args, command); + + // Reporting + StringBuilder cmdLine = new StringBuilder(); + for (String cmd : args) + cmdLine.append(cmd).append(' '); + System.out.println("Command line: [" + cmdLine.toString() + "]"); + + return new ProcessBuilder(args.toArray(new String[args.size()])); + } + + private static void printStack(Thread t, StackTraceElement[] stack) { + System.out.println("\t" + t + + " stack: (length = " + stack.length + ")"); + if (t != null) { + for (StackTraceElement stack1 : stack) { + System.out.println("\t" + stack1); + } + System.out.println(); + } + } + + /** + * Executes a test jvm process, waits for it to finish and returns the process output. + * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added. + * The java from the test.jdk is used to execute the command. + * + * The command line will be like: + * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds + * + * The jvm process will have exited before this method returns. + * + * @param cmds User specifed arguments. + * @return The output from the process. + */ + public static OutputAnalyzer executeTestJvm(String... cmds) throws Exception { + ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(cmds)); + return executeProcess(pb); + } + + /** + * Executes a process, waits for it to finish and returns the process output. + * The process will have exited before this method returns. + * @param pb The ProcessBuilder to execute. + * @return The {@linkplain OutputAnalyzer} instance wrapping the process. + */ + public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = null; + Process p = null; + boolean failed = false; + try { + p = pb.start(); + output = new OutputAnalyzer(p); + p.waitFor(); + + return output; + } catch (Throwable t) { + if (p != null) { + p.destroyForcibly().waitFor(); + } + + failed = true; + System.out.println("executeProcess() failed: " + t); + throw t; + } finally { + if (failed) { + System.err.println(getProcessLog(pb, output)); + } + } + } + + /** + * Executes a process, waits for it to finish and returns the process output. + * + * The process will have exited before this method returns. + * + * @param cmds The command line to execute. + * @return The output from the process. + */ + public static OutputAnalyzer executeProcess(String... cmds) throws Throwable { + return executeProcess(new ProcessBuilder(cmds)); + } + + /** + * Used to log command line, stdout, stderr and exit code from an executed process. + * @param pb The executed process. + * @param output The output from the process. + */ + public static String getProcessLog(ProcessBuilder pb, OutputAnalyzer output) { + String stderr = output == null ? "null" : output.getStderr(); + String stdout = output == null ? "null" : output.getStdout(); + String exitValue = output == null ? "null": Integer.toString(output.getExitValue()); + StringBuilder logMsg = new StringBuilder(); + final String nl = System.getProperty("line.separator"); + logMsg.append("--- ProcessLog ---" + nl); + logMsg.append("cmd: " + getCommandLine(pb) + nl); + logMsg.append("exitvalue: " + exitValue + nl); + logMsg.append("stderr: " + stderr + nl); + logMsg.append("stdout: " + stdout + nl); + + return logMsg.toString(); + } + + /** + * @return The full command line for the ProcessBuilder. + */ + public static String getCommandLine(ProcessBuilder pb) { + if (pb == null) { + return "null"; + } + StringBuilder cmd = new StringBuilder(); + for (String s : pb.command()) { + cmd.append(s).append(" "); + } + return cmd.toString().trim(); + } + + /** + * Executes a process, waits for it to finish, prints the process output + * to stdout, and returns the process output. + * + * The process will have exited before this method returns. + * + * @param cmds The command line to execute. + * @return The {@linkplain OutputAnalyzer} instance wrapping the process. + */ + public static OutputAnalyzer executeCommand(String... cmds) + throws Throwable { + String cmdLine = Arrays.stream(cmds).collect(Collectors.joining(" ")); + System.out.println("Command line: [" + cmdLine + "]"); + OutputAnalyzer analyzer = ProcessTools.executeProcess(cmds); + System.out.println(analyzer.getOutput()); + return analyzer; + } + + /** + * Executes a process, waits for it to finish, prints the process output + * to stdout and returns the process output. + * + * The process will have exited before this method returns. + * + * @param pb The ProcessBuilder to execute. + * @return The {@linkplain OutputAnalyzer} instance wrapping the process. + */ + public static OutputAnalyzer executeCommand(ProcessBuilder pb) + throws Throwable { + String cmdLine = pb.command().stream().collect(Collectors.joining(" ")); + System.out.println("Command line: [" + cmdLine + "]"); + OutputAnalyzer analyzer = ProcessTools.executeProcess(pb); + System.out.println(analyzer.getOutput()); + return analyzer; + } + + private static class ProcessImpl extends Process { + + private final Process p; + private final Future stdoutTask; + private final Future stderrTask; + + public ProcessImpl(Process p, Future stdoutTask, Future stderrTask) { + this.p = p; + this.stdoutTask = stdoutTask; + this.stderrTask = stderrTask; + } + + @Override + public OutputStream getOutputStream() { + return p.getOutputStream(); + } + + @Override + public InputStream getInputStream() { + return p.getInputStream(); + } + + @Override + public InputStream getErrorStream() { + return p.getErrorStream(); + } + + @Override + public int waitFor() throws InterruptedException { + int rslt = p.waitFor(); + waitForStreams(); + return rslt; + } + + @Override + public int exitValue() { + return p.exitValue(); + } + + @Override + public void destroy() { + p.destroy(); + } + + @Override + public long getPid() { + return p.getPid(); + } + + @Override + public boolean isAlive() { + return p.isAlive(); + } + + @Override + public Process destroyForcibly() { + return p.destroyForcibly(); + } + + @Override + public boolean waitFor(long timeout, TimeUnit unit) throws InterruptedException { + boolean rslt = p.waitFor(timeout, unit); + if (rslt) { + waitForStreams(); + } + return rslt; + } + + private void waitForStreams() throws InterruptedException { + try { + stdoutTask.get(); + } catch (ExecutionException e) { + } + try { + stderrTask.get(); + } catch (ExecutionException e) { + } + } + } +} diff --git a/test/lib/share/classes/jdk/test/lib/process/StreamPumper.java b/test/lib/share/classes/jdk/test/lib/process/StreamPumper.java new file mode 100644 index 00000000000..b1780c4ef08 --- /dev/null +++ b/test/lib/share/classes/jdk/test/lib/process/StreamPumper.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.test.lib.process; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.atomic.AtomicBoolean; + +public final class StreamPumper implements Runnable { + + private static final int BUF_SIZE = 256; + + /** + * Pump will be called by the StreamPumper to process the incoming data + */ + abstract public static class Pump { + abstract void register(StreamPumper d); + } + + /** + * OutputStream -> Pump adapter + */ + final public static class StreamPump extends Pump { + private final OutputStream out; + public StreamPump(OutputStream out) { + this.out = out; + } + + @Override + void register(StreamPumper sp) { + sp.addOutputStream(out); + } + } + + /** + * Used to process the incoming data line-by-line + */ + abstract public static class LinePump extends Pump { + @Override + final void register(StreamPumper sp) { + sp.addLineProcessor(this); + } + + abstract protected void processLine(String line); + } + + private final InputStream in; + private final Set outStreams = new HashSet<>(); + private final Set linePumps = new HashSet<>(); + + private final AtomicBoolean processing = new AtomicBoolean(false); + private final FutureTask processingTask = new FutureTask<>(this, null); + + public StreamPumper(InputStream in) { + this.in = in; + } + + /** + * Create a StreamPumper that reads from in and writes to out. + * + * @param in The stream to read from. + * @param out The stream to write to. + */ + public StreamPumper(InputStream in, OutputStream out) { + this(in); + this.addOutputStream(out); + } + + /** + * Implements Thread.run(). Continuously read from {@code in} and write to + * {@code out} until {@code in} has reached end of stream. Abort on + * interruption. Abort on IOExceptions. + */ + @Override + public void run() { + try (BufferedInputStream is = new BufferedInputStream(in)) { + ByteArrayOutputStream lineBos = new ByteArrayOutputStream(); + byte[] buf = new byte[BUF_SIZE]; + int len = 0; + int linelen = 0; + + while ((len = is.read(buf)) > 0 && !Thread.interrupted()) { + for(OutputStream out : outStreams) { + out.write(buf, 0, len); + } + if (!linePumps.isEmpty()) { + int i = 0; + int lastcrlf = -1; + while (i < len) { + if (buf[i] == '\n' || buf[i] == '\r') { + int bufLinelen = i - lastcrlf - 1; + if (bufLinelen > 0) { + lineBos.write(buf, lastcrlf + 1, bufLinelen); + } + linelen += bufLinelen; + + if (linelen > 0) { + lineBos.flush(); + final String line = lineBos.toString(); + linePumps.stream().forEach((lp) -> { + lp.processLine(line); + }); + lineBos.reset(); + linelen = 0; + } + lastcrlf = i; + } + + i++; + } + if (lastcrlf == -1) { + lineBos.write(buf, 0, len); + linelen += len; + } else if (lastcrlf < len - 1) { + lineBos.write(buf, lastcrlf + 1, len - lastcrlf - 1); + linelen += len - lastcrlf - 1; + } + } + } + + } catch (IOException e) { + e.printStackTrace(); + } finally { + for(OutputStream out : outStreams) { + try { + out.flush(); + } catch (IOException e) {} + } + try { + in.close(); + } catch (IOException e) {} + } + } + + final void addOutputStream(OutputStream out) { + outStreams.add(out); + } + + final void addLineProcessor(LinePump lp) { + linePumps.add(lp); + } + + final public StreamPumper addPump(Pump ... pump) { + if (processing.get()) { + throw new IllegalStateException("Can not modify pumper while " + + "processing is in progress"); + } + for(Pump p : pump) { + p.register(this); + } + return this; + } + + final public Future process() { + if (!processing.compareAndSet(false, true)) { + throw new IllegalStateException("Can not re-run the processing"); + } + Thread t = new Thread(new Runnable() { + @Override + public void run() { + processingTask.run(); + } + }); + t.setDaemon(true); + t.start(); + + return processingTask; + } +} From 6ffba3b398f03d29ed0778e5ca6534540c1d89a3 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Thu, 3 Dec 2015 15:22:31 +0300 Subject: [PATCH 019/215] 8134152: Public API for java 8 DataFlavor fields do not have @since tag Reviewed-by: ssadetsky, alexsch --- .../share/classes/java/awt/datatransfer/DataFlavor.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java index 5f05177be39..becfd0563ba 100644 --- a/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java +++ b/jdk/src/java.datatransfer/share/classes/java/awt/datatransfer/DataFlavor.java @@ -289,6 +289,8 @@ public class DataFlavor implements Externalizable, Cloneable { * representationClass = String * mimeType = "text/html" * + * + * @since 1.8 */ public static DataFlavor selectionHtmlFlavor = initHtmlDataFlavor("selection"); @@ -301,6 +303,8 @@ public class DataFlavor implements Externalizable, Cloneable { * representationClass = String * mimeType = "text/html" * + * + * @since 1.8 */ public static DataFlavor fragmentHtmlFlavor = initHtmlDataFlavor("fragment"); @@ -314,6 +318,8 @@ public class DataFlavor implements Externalizable, Cloneable { * representationClass = String * mimeType = "text/html" * + * + * @since 1.8 */ public static DataFlavor allHtmlFlavor = initHtmlDataFlavor("all"); From 3096b2cc2f538b50b73971d8996c2c90a60da380 Mon Sep 17 00:00:00 2001 From: Rajeev Chamyal Date: Fri, 4 Dec 2015 09:56:50 +0400 Subject: [PATCH 020/215] 8067660: JFileChooser create new folder fails silently Reviewed-by: alexsch, psadhukhan --- .../swing/filechooser/FileSystemView.java | 13 +- .../JFileChooser/8067660/FileChooserTest.java | 250 ++++++++++++++++++ 2 files changed, 259 insertions(+), 4 deletions(-) create mode 100644 jdk/test/javax/swing/JFileChooser/8067660/FileChooserTest.java diff --git a/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java b/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java index 54cd7c037d4..bbc35bf9c1d 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java @@ -663,7 +663,9 @@ class UnixFileSystemView extends FileSystemView { if(newFolder.exists()) { throw new IOException("Directory already exists:" + newFolder.getAbsolutePath()); } else { - newFolder.mkdirs(); + if(!newFolder.mkdirs()) { + throw new IOException(newFolder.getAbsolutePath()); + } } return newFolder; @@ -773,7 +775,9 @@ class WindowsFileSystemView extends FileSystemView { if(newFolder.exists()) { throw new IOException("Directory already exists:" + newFolder.getAbsolutePath()); } else { - newFolder.mkdirs(); + if(!newFolder.mkdirs()) { + throw new IOException(newFolder.getAbsolutePath()); + } } return newFolder; @@ -842,9 +846,10 @@ class GenericFileSystemView extends FileSystemView { if(newFolder.exists()) { throw new IOException("Directory already exists:" + newFolder.getAbsolutePath()); } else { - newFolder.mkdirs(); + if(!newFolder.mkdirs()) { + throw new IOException(newFolder.getAbsolutePath()); + } } - return newFolder; } diff --git a/jdk/test/javax/swing/JFileChooser/8067660/FileChooserTest.java b/jdk/test/javax/swing/JFileChooser/8067660/FileChooserTest.java new file mode 100644 index 00000000000..acd49add15f --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/8067660/FileChooserTest.java @@ -0,0 +1,250 @@ +/* + * 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 8067660 + * @summary JFileChooser create new folder fails silently + * @requires (os.family == "windows") + * @run main/manual FileChooserTest + */ +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +public class FileChooserTest { + + private static boolean theTestPassed; + private static boolean testGeneratedInterrupt; + private static Thread mainThread; + private static int sleepTime = 30000; + public static JFileChooser fileChooser; + + private static void init() throws Exception { + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + String[] instructions + = { + "1) Create a folder with read only permissions", + "2) Click on run test button.It will open a open dialog" + + " Navigate to the newly created read only folder", + "3) Click on the create new folder button in open dialog", + "4) If an error message does not pops up" + + "test failed otherwise passed.", + "5) Pressing Pass/Fail button will mark test as " + + "pass/fail and will shutdown JVM"}; + + Sysout.createDialogWithInstructions(instructions); + Sysout.printInstructions(instructions); + } + }); + } + + /** + * *************************************************** + * Standard Test Machinery Section DO NOT modify anything in this section -- + * it's a standard chunk of code which has all of the synchronisation + * necessary for the test harness. By keeping it the same in all tests, it + * is easier to read and understand someone else's test, as well as insuring + * that all tests behave correctly with the test harness. There is a section + * following this for test-defined classes + */ + public static void main(String args[]) throws Exception { + + mainThread = Thread.currentThread(); + try { + init(); + } catch (Exception ex) { + return; + } + try { + mainThread.sleep(sleepTime); + } catch (InterruptedException ex) { + Sysout.dispose(); + if (!theTestPassed && testGeneratedInterrupt) { + throw new RuntimeException("Test Failed"); + } + } + if (!testGeneratedInterrupt) { + Sysout.dispose(); + throw new RuntimeException("Test Failed"); + } + } + + public static synchronized void pass() { + theTestPassed = true; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } + + public static synchronized void fail() { + theTestPassed = false; + testGeneratedInterrupt = true; + mainThread.interrupt(); + } +} + +/** + * This is part of the standard test machinery. It creates a dialog (with the + * instructions), and is the interface for sending text messages to the user. To + * print the instructions, send an array of strings to Sysout.createDialog + * WithInstructions method. Put one line of instructions per array entry. To + * display a message for the tester to see, simply call Sysout.println with the + * string to be displayed. This mimics System.out.println but works within the + * test harness as well as standalone. + */ +class Sysout { + + private static TestDialog dialog; + private static JFrame frame; + + public static void createDialogWithInstructions(String[] instructions) { + frame = new JFrame(); + dialog = new TestDialog(frame, "Instructions"); + dialog.printInstructions(instructions); + dialog.setVisible(true); + println("Any messages for the tester will display here."); + } + + public static void printInstructions(String[] instructions) { + dialog.printInstructions(instructions); + } + + public static void println(String messageIn) { + dialog.displayMessage(messageIn); + } + + public static void dispose() { + Sysout.println("Shutting down the Java process.."); + if(FileChooserTest.fileChooser != null) { + FileChooserTest.fileChooser.cancelSelection(); + } + frame.dispose(); + dialog.dispose(); + } +} + +/** + * This is part of the standard test machinery. It provides a place for the test + * instructions to be displayed, and a place for interactive messages to the + * user to be displayed. To have the test instructions displayed, see Sysout. To + * have a message to the user be displayed, see Sysout. Do not call anything in + * this dialog directly. + */ +class TestDialog extends JDialog { + + private TextArea instructionsText; + private TextArea messageText; + private int maxStringLength = 80; + private Panel buttonP = new Panel(); + private JButton run = new JButton("Run"); + private JButton passB = new JButton("Pass"); + private JButton failB = new JButton("Fail"); + + public TestDialog(JFrame frame, String name) { + super(frame, name); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + int scrollBoth = TextArea.SCROLLBARS_BOTH; + instructionsText = new TextArea("", 15, maxStringLength, scrollBoth); + add("North", instructionsText); + + messageText = new TextArea("", 5, maxStringLength, scrollBoth); + add("Center", messageText); + + buttonP.add("East", run); + buttonP.add("East", passB); + buttonP.add("West", failB); + passB.setEnabled(false); + failB.setEnabled(false); + add("South", buttonP); + + run.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent ae) { + FileChooserTest.fileChooser = new JFileChooser(); + FileChooserTest.fileChooser.showOpenDialog(null); + passB.setEnabled(true); + failB.setEnabled(true); + } + }); + + passB.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent ae) { + FileChooserTest.pass(); + } + }); + + failB.addActionListener(new ActionListener() { + + @Override + public void actionPerformed(ActionEvent ae) { + FileChooserTest.fail(); + } + }); + pack(); + + setVisible(true); + } + + public void printInstructions(String[] instructions) { + instructionsText.setText(""); + + String printStr, remainingStr; + for (String instruction : instructions) { + remainingStr = instruction; + while (remainingStr.length() > 0) { + if (remainingStr.length() >= maxStringLength) { + int posOfSpace = remainingStr. + lastIndexOf(' ', maxStringLength - 1); + + if (posOfSpace <= 0) { + posOfSpace = maxStringLength - 1; + } + + printStr = remainingStr.substring(0, posOfSpace + 1); + remainingStr = remainingStr.substring(posOfSpace + 1); + } else { + printStr = remainingStr; + remainingStr = ""; + } + instructionsText.append(printStr + "\n"); + } + } + + } + + public void displayMessage(String messageIn) { + messageText.append(messageIn + "\n"); + } +} From 9c2dc1edf517c9e025972c167453594127db9a01 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 4 Dec 2015 13:52:21 +0300 Subject: [PATCH 021/215] 8140530: Creating a VolatileImage with size 0, 0 results in no longer working g2d.drawStri Reviewed-by: flar, serb --- .../sun/awt/image/SunVolatileImage.java | 4 ++ .../native/common/java2d/x11/X11SurfaceData.c | 9 ++++ .../image/VolatileImage/VolatileImageBug.java | 52 +++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 jdk/test/java/awt/image/VolatileImage/VolatileImageBug.java diff --git a/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java b/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java index 00c8911f696..1ee5c4019f1 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/image/SunVolatileImage.java @@ -70,6 +70,10 @@ public class SunVolatileImage extends VolatileImage { this.comp = comp; this.graphicsConfig = graphicsConfig; + if (width <= 0 || height <= 0) { + throw new IllegalArgumentException("Width (" + width + ")" + + " and height (" + height + ") cannot be <= 0"); + } this.width = width; this.height = height; this.forcedAccelSurfaceType = accType; diff --git a/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c b/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c index d9af8ddf6e1..e6597a4723c 100644 --- a/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c +++ b/jdk/src/java.desktop/unix/native/common/java2d/x11/X11SurfaceData.c @@ -438,6 +438,15 @@ jboolean XShared_initSurface(JNIEnv *env, X11SDOps *xsdo, jint depth, jint width xsdo->drawable = drawable; xsdo->isPixmap = JNI_FALSE; } else { + /* + * width , height must be nonzero otherwise XCreatePixmap + * generates BadValue in error_handler + */ + if (width <= 0 || height <= 0) { + JNU_ThrowOutOfMemoryError(env, + "Can't create offscreen surface"); + return JNI_FALSE; + } xsdo->isPixmap = JNI_TRUE; /* REMIND: workaround for bug 4420220 on pgx32 boards: don't use DGA with pixmaps unless USE_DGA_PIXMAPS is set. diff --git a/jdk/test/java/awt/image/VolatileImage/VolatileImageBug.java b/jdk/test/java/awt/image/VolatileImage/VolatileImageBug.java new file mode 100644 index 00000000000..70ca2b00840 --- /dev/null +++ b/jdk/test/java/awt/image/VolatileImage/VolatileImageBug.java @@ -0,0 +1,52 @@ +/* + * 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. + */ +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.image.VolatileImage; + +/** + * @test + * @bug 8140530 + * @run main VolatileImageBug + * @summary Creating volatileimage(0,0) should throw IAE + */ +public class VolatileImageBug { + public static void main(String[] args) { + + boolean iaeThrown = false; + GraphicsEnvironment ge = GraphicsEnvironment. + getLocalGraphicsEnvironment(); + GraphicsConfiguration gc = ge.getDefaultScreenDevice(). + getDefaultConfiguration(); + try { + VolatileImage volatileImage = gc.createCompatibleVolatileImage(0, 0); + } catch (IllegalArgumentException iae) { + iaeThrown = true; + } + if (!iaeThrown) { + throw new RuntimeException ("IllegalArgumentException not thrown " + + "for createCompatibleVolatileImage(0,0)"); + } + } +} + From c64b2175e7f4aac94f48bc8e26e9d8db73b9fc9b Mon Sep 17 00:00:00 2001 From: Andreas Eriksson Date: Fri, 4 Dec 2015 14:06:38 +0100 Subject: [PATCH 022/215] 6869327: Add new C2 flag to keep safepoints in counted loops Reviewed-by: kvn, shade --- hotspot/src/share/vm/opto/c2_globals.hpp | 3 + hotspot/src/share/vm/opto/loopnode.cpp | 96 +++++++++++-------- hotspot/src/share/vm/opto/loopnode.hpp | 5 +- .../loopopts/UseCountedLoopSafepoints.java | 68 +++++++++++++ 4 files changed, 129 insertions(+), 43 deletions(-) create mode 100644 hotspot/test/compiler/loopopts/UseCountedLoopSafepoints.java diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index 0001104c001..6a08d42f052 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -213,6 +213,9 @@ notproduct(bool, TraceProfileTripCount, false, \ "Trace profile loop trip count information") \ \ + product(bool, UseCountedLoopSafepoints, false, \ + "Force counted loops to keep a safepoint") \ + \ product(bool, UseLoopPredicate, true, \ "Generate a predicate to select fast/slow loop versions") \ \ diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp index 953364397ab..db0b3c83c84 100644 --- a/hotspot/src/share/vm/opto/loopnode.cpp +++ b/hotspot/src/share/vm/opto/loopnode.cpp @@ -690,14 +690,16 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { } // LoopLimitCheck - // Check for SafePoint on backedge and remove - Node *sfpt = x->in(LoopNode::LoopBackControl); - if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { - lazy_replace( sfpt, iftrue ); - if (loop->_safepts != NULL) { - loop->_safepts->yank(sfpt); + if (!UseCountedLoopSafepoints) { + // Check for SafePoint on backedge and remove + Node *sfpt = x->in(LoopNode::LoopBackControl); + if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { + lazy_replace( sfpt, iftrue ); + if (loop->_safepts != NULL) { + loop->_safepts->yank(sfpt); + } + loop->_tail = iftrue; } - loop->_tail = iftrue; } // Build a canonical trip test. @@ -786,12 +788,14 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { lazy_replace( x, l ); set_idom(l, init_control, dom_depth(x)); - // Check for immediately preceding SafePoint and remove - Node *sfpt2 = le->in(0); - if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) { - lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control)); - if (loop->_safepts != NULL) { - loop->_safepts->yank(sfpt2); + if (!UseCountedLoopSafepoints) { + // Check for immediately preceding SafePoint and remove + Node *sfpt2 = le->in(0); + if (sfpt2->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt2)) { + lazy_replace( sfpt2, sfpt2->in(TypeFunc::Control)); + if (loop->_safepts != NULL) { + loop->_safepts->yank(sfpt2); + } } } @@ -1813,6 +1817,33 @@ void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) { } } +void IdealLoopTree::remove_safepoints(PhaseIdealLoop* phase, bool keep_one) { + // Look for a safepoint on the idom-path. + Node* keep = NULL; + if (keep_one) { + // Keep one if possible + for (Node* i = tail(); i != _head; i = phase->idom(i)) { + if (i->Opcode() == Op_SafePoint && phase->get_loop(i) == this) { + keep = i; + break; // Found one + } + } + } + + // Delete other safepoints in this loop. + Node_List* sfpts = _safepts; + if (sfpts != NULL) { + assert(keep == NULL || keep->Opcode() == Op_SafePoint, "not safepoint"); + for (uint i = 0; i < sfpts->size(); i++) { + Node* n = sfpts->at(i); + assert(phase->get_loop(n) == this, ""); + if (n != keep && phase->is_deleteable_safept(n)) { + phase->lazy_replace(n, n->in(TypeFunc::Control)); + } + } + } +} + //------------------------------counted_loop----------------------------------- // Convert to counted loops where possible void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) { @@ -1824,42 +1855,23 @@ void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) { if (_head->is_CountedLoop() || phase->is_counted_loop(_head, this)) { - _has_sfpt = 1; // Indicate we do not need a safepoint here - // Look for safepoints to remove. - Node_List* sfpts = _safepts; - if (sfpts != NULL) { - for (uint i = 0; i < sfpts->size(); i++) { - Node* n = sfpts->at(i); - assert(phase->get_loop(n) == this, ""); - if (phase->is_deleteable_safept(n)) { - phase->lazy_replace(n, n->in(TypeFunc::Control)); - } - } + if (!UseCountedLoopSafepoints) { + // Indicate we do not need a safepoint here + _has_sfpt = 1; } + // Remove safepoints + bool keep_one_sfpt = !(_has_call || _has_sfpt); + remove_safepoints(phase, keep_one_sfpt); + // Look for induction variables phase->replace_parallel_iv(this); } else if (_parent != NULL && !_irreducible) { - // Not a counted loop. - // Look for a safepoint on the idom-path. - Node* sfpt = tail(); - for (; sfpt != _head; sfpt = phase->idom(sfpt)) { - if (sfpt->Opcode() == Op_SafePoint && phase->get_loop(sfpt) == this) - break; // Found one - } - // Delete other safepoints in this loop. - Node_List* sfpts = _safepts; - if (sfpts != NULL && sfpt != _head && sfpt->Opcode() == Op_SafePoint) { - for (uint i = 0; i < sfpts->size(); i++) { - Node* n = sfpts->at(i); - assert(phase->get_loop(n) == this, ""); - if (n != sfpt && phase->is_deleteable_safept(n)) { - phase->lazy_replace(n, n->in(TypeFunc::Control)); - } - } - } + // Not a counted loop. Keep one safepoint. + bool keep_one_sfpt = true; + remove_safepoints(phase, keep_one_sfpt); } // Recursively diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index fd736bbf426..59cfc690c7e 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -429,6 +429,9 @@ public: // encountered. void allpaths_check_safepts(VectorSet &visited, Node_List &stack); + // Remove safepoints from loop. Optionally keeping one. + void remove_safepoints(PhaseIdealLoop* phase, bool keep_one); + // Convert to counted loops where possible void counted_loop( PhaseIdealLoop *phase ); diff --git a/hotspot/test/compiler/loopopts/UseCountedLoopSafepoints.java b/hotspot/test/compiler/loopopts/UseCountedLoopSafepoints.java new file mode 100644 index 00000000000..c769b5b5aba --- /dev/null +++ b/hotspot/test/compiler/loopopts/UseCountedLoopSafepoints.java @@ -0,0 +1,68 @@ +/* + * 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 6869327 + * @summary Test that C2 flag UseCountedLoopSafepoints ensures a safepoint is kept in a CountedLoop + * @library /testlibrary + * @modules java.base + * @run main UseCountedLoopSafepoints + */ + +import java.util.concurrent.atomic.AtomicLong; +import jdk.test.lib.ProcessTools; +import jdk.test.lib.OutputAnalyzer; + +public class UseCountedLoopSafepoints { + private static final AtomicLong _num = new AtomicLong(0); + + // Uses the fact that an EnableBiasedLocking vmop will be started + // after 500ms, while we are still in the loop. If there is a + // safepoint in the counted loop, then we will reach safepoint + // very quickly. Otherwise SafepointTimeout will be hit. + public static void main (String args[]) throws Exception { + if (args.length == 1) { + final int loops = Integer.parseInt(args[0]); + for (int i = 0; i < loops; i++) { + _num.addAndGet(1); + } + } else { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:-TieredCompilation", + "-XX:+UseBiasedLocking", + "-XX:BiasedLockingStartupDelay=500", + "-XX:+SafepointTimeout", + "-XX:SafepointTimeoutDelay=2000", + "-XX:+UseCountedLoopSafepoints", + "UseCountedLoopSafepoints", + "2000000000" + ); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Timeout detected"); + output.shouldHaveExitValue(0); + } + } +} From 0fba365de2b950d02c586068f86d12509cede415 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Fri, 4 Dec 2015 16:23:39 +0100 Subject: [PATCH 023/215] 8136445: Performance issue with Nashorn and C2's global code motion Reviewed-by: kvn --- hotspot/src/share/vm/opto/block.hpp | 6 +-- hotspot/src/share/vm/opto/gcm.cpp | 63 +++++++++++++++++------------ 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/hotspot/src/share/vm/opto/block.hpp b/hotspot/src/share/vm/opto/block.hpp index ad30a167130..d84529deb88 100644 --- a/hotspot/src/share/vm/opto/block.hpp +++ b/hotspot/src/share/vm/opto/block.hpp @@ -419,12 +419,12 @@ class PhaseCFG : public Phase { void global_code_motion(); // Schedule Nodes early in their basic blocks. - bool schedule_early(VectorSet &visited, Node_List &roots); + bool schedule_early(VectorSet &visited, Node_Stack &roots); // For each node, find the latest block it can be scheduled into // and then select the cheapest block between the latest and earliest // block to place the node. - void schedule_late(VectorSet &visited, Node_List &stack); + void schedule_late(VectorSet &visited, Node_Stack &stack); // Compute the (backwards) latency of a node from a single use int latency_from_use(Node *n, const Node *def, Node *use); @@ -433,7 +433,7 @@ class PhaseCFG : public Phase { void partial_latency_of_defs(Node *n); // Compute the instruction global latency with a backwards walk - void compute_latencies_backwards(VectorSet &visited, Node_List &stack); + void compute_latencies_backwards(VectorSet &visited, Node_Stack &stack); // Pick a block between early and late that is a cheaper alternative // to late. Helper for schedule_late. diff --git a/hotspot/src/share/vm/opto/gcm.cpp b/hotspot/src/share/vm/opto/gcm.cpp index 70c17ad8b1c..833be199daa 100644 --- a/hotspot/src/share/vm/opto/gcm.cpp +++ b/hotspot/src/share/vm/opto/gcm.cpp @@ -228,18 +228,19 @@ static Block* find_deepest_input(Node* n, const PhaseCFG* cfg) { // Find the earliest Block any instruction can be placed in. Some instructions // are pinned into Blocks. Unpinned instructions can appear in last block in // which all their inputs occur. -bool PhaseCFG::schedule_early(VectorSet &visited, Node_List &roots) { +bool PhaseCFG::schedule_early(VectorSet &visited, Node_Stack &roots) { // Allocate stack with enough space to avoid frequent realloc - Node_Stack nstack(roots.Size() + 8); + Node_Stack nstack(roots.size() + 8); // _root will be processed among C->top() inputs - roots.push(C->top()); + roots.push(C->top(), 0); visited.set(C->top()->_idx); while (roots.size() != 0) { // Use local variables nstack_top_n & nstack_top_i to cache values // on stack's top. - Node* parent_node = roots.pop(); + Node* parent_node = roots.node(); uint input_index = 0; + roots.pop(); while (true) { if (input_index == 0) { @@ -286,7 +287,7 @@ bool PhaseCFG::schedule_early(VectorSet &visited, Node_List &roots) { break; } else if (!is_visited) { // Visit this guy later, using worklist - roots.push(in); + roots.push(in, 0); } } @@ -791,23 +792,23 @@ private: public: // Constructor for the iterator - Node_Backward_Iterator(Node *root, VectorSet &visited, Node_List &stack, PhaseCFG &cfg); + Node_Backward_Iterator(Node *root, VectorSet &visited, Node_Stack &stack, PhaseCFG &cfg); // Postincrement operator to iterate over the nodes Node *next(); private: VectorSet &_visited; - Node_List &_stack; + Node_Stack &_stack; PhaseCFG &_cfg; }; // Constructor for the Node_Backward_Iterator -Node_Backward_Iterator::Node_Backward_Iterator( Node *root, VectorSet &visited, Node_List &stack, PhaseCFG &cfg) +Node_Backward_Iterator::Node_Backward_Iterator( Node *root, VectorSet &visited, Node_Stack &stack, PhaseCFG &cfg) : _visited(visited), _stack(stack), _cfg(cfg) { // The stack should contain exactly the root stack.clear(); - stack.push(root); + stack.push(root, root->outcnt()); // Clear the visited bits visited.Clear(); @@ -820,12 +821,14 @@ Node *Node_Backward_Iterator::next() { if ( !_stack.size() ) return NULL; - // '_stack' is emulating a real _stack. The 'visit-all-users' loop has been - // made stateless, so I do not need to record the index 'i' on my _stack. - // Instead I visit all users each time, scanning for unvisited users. // I visit unvisited not-anti-dependence users first, then anti-dependent - // children next. - Node *self = _stack.pop(); + // children next. I iterate backwards to support removal of nodes. + // The stack holds states consisting of 3 values: + // current Def node, flag which indicates 1st/2nd pass, index of current out edge + Node *self = (Node*)(((uintptr_t)_stack.node()) & ~1); + bool iterate_anti_dep = (((uintptr_t)_stack.node()) & 1); + uint idx = MIN2(_stack.index(), self->outcnt()); // Support removal of nodes. + _stack.pop(); // I cycle here when I am entering a deeper level of recursion. // The key variable 'self' was set prior to jumping here. @@ -841,9 +844,9 @@ Node *Node_Backward_Iterator::next() { Node *unvisited = NULL; // Unvisited anti-dependent Node, if any // Scan for unvisited nodes - for (DUIterator_Fast imax, i = self->fast_outs(imax); i < imax; i++) { + while (idx > 0) { // For all uses, schedule late - Node* n = self->fast_out(i); // Use + Node* n = self->raw_out(--idx); // Use // Skip already visited children if ( _visited.test(n->_idx) ) @@ -863,19 +866,31 @@ Node *Node_Backward_Iterator::next() { unvisited = n; // Found unvisited // Check for possible-anti-dependent - if( !n->needs_anti_dependence_check() ) - break; // Not visited, not anti-dep; schedule it NOW + // 1st pass: No such nodes, 2nd pass: Only such nodes. + if (n->needs_anti_dependence_check() == iterate_anti_dep) { + unvisited = n; // Found unvisited + break; + } } // Did I find an unvisited not-anti-dependent Node? - if ( !unvisited ) + if (!unvisited) { + if (!iterate_anti_dep) { + // 2nd pass: Iterate over nodes which needs_anti_dependence_check. + iterate_anti_dep = true; + idx = self->outcnt(); + continue; + } break; // All done with children; post-visit 'self' + } // Visit the unvisited Node. Contains the obvious push to // indicate I'm entering a deeper level of recursion. I push the // old state onto the _stack and set a new state and loop (recurse). - _stack.push(self); + _stack.push((Node*)((uintptr_t)self | (uintptr_t)iterate_anti_dep), idx); self = unvisited; + iterate_anti_dep = false; + idx = self->outcnt(); } // End recursion loop return self; @@ -883,7 +898,7 @@ Node *Node_Backward_Iterator::next() { //------------------------------ComputeLatenciesBackwards---------------------- // Compute the latency of all the instructions. -void PhaseCFG::compute_latencies_backwards(VectorSet &visited, Node_List &stack) { +void PhaseCFG::compute_latencies_backwards(VectorSet &visited, Node_Stack &stack) { #ifndef PRODUCT if (trace_opto_pipelining()) tty->print("\n#---- ComputeLatenciesBackwards ----\n"); @@ -1157,7 +1172,7 @@ Block* PhaseCFG::hoist_to_cheaper_block(Block* LCA, Block* early, Node* self) { // dominator tree of all USES of a value. Pick the block with the least // loop nesting depth that is lowest in the dominator tree. extern const char must_clone[]; -void PhaseCFG::schedule_late(VectorSet &visited, Node_List &stack) { +void PhaseCFG::schedule_late(VectorSet &visited, Node_Stack &stack) { #ifndef PRODUCT if (trace_opto_pipelining()) tty->print("\n#---- schedule_late ----\n"); @@ -1313,9 +1328,7 @@ void PhaseCFG::global_code_motion() { // instructions are pinned into Blocks. Unpinned instructions can // appear in last block in which all their inputs occur. visited.Clear(); - Node_List stack(arena); - // Pre-grow the list - stack.map((C->live_nodes() >> 1) + 16, NULL); + Node_Stack stack(arena, (C->live_nodes() >> 2) + 16); // pre-grow if (!schedule_early(visited, stack)) { // Bailout without retry C->record_method_not_compilable("early schedule failed"); From 8c5da27f19d26be9b4f727c7ff4a17f99a25a520 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Fri, 4 Dec 2015 16:38:04 +0100 Subject: [PATCH 024/215] 8144019: PPC64 C1: Introduce Client Compiler Reviewed-by: goetz --- hotspot/make/aix/Makefile | 6 +- hotspot/make/aix/makefiles/fastdebug.make | 2 +- hotspot/make/aix/makefiles/tiered.make | 32 + hotspot/make/linux/Makefile | 8 - hotspot/src/cpu/ppc/vm/assembler_ppc.cpp | 5 +- hotspot/src/cpu/ppc/vm/assembler_ppc.hpp | 68 +- .../src/cpu/ppc/vm/assembler_ppc.inline.hpp | 10 +- hotspot/src/cpu/ppc/vm/c1_CodeStubs_ppc.cpp | 527 +++ hotspot/src/cpu/ppc/vm/c1_Defs_ppc.hpp | 76 + hotspot/src/cpu/ppc/vm/c1_FpuStackSim_ppc.hpp | 32 + hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.cpp | 394 +++ hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.hpp | 202 ++ .../src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp | 3133 +++++++++++++++++ .../src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp | 69 + .../src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp | 1429 ++++++++ hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.cpp | 34 + hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.hpp | 73 + .../src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp | 486 +++ .../src/cpu/ppc/vm/c1_MacroAssembler_ppc.hpp | 93 + hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp | 1020 ++++++ hotspot/src/cpu/ppc/vm/c1_globals_ppc.hpp | 68 + hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp | 2 +- hotspot/src/cpu/ppc/vm/c2_init_ppc.cpp | 8 +- hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp | 15 +- hotspot/src/cpu/ppc/vm/frame_ppc.cpp | 37 +- hotspot/src/cpu/ppc/vm/frame_ppc.hpp | 5 +- hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp | 3 - .../src/cpu/ppc/vm/globalDefinitions_ppc.hpp | 3 + hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp | 59 +- hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp | 4 +- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp | 393 ++- hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp | 47 +- .../cpu/ppc/vm/macroAssembler_ppc.inline.hpp | 48 +- hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp | 7 +- hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp | 55 +- hotspot/src/cpu/ppc/vm/nativeInst_ppc.hpp | 123 +- hotspot/src/cpu/ppc/vm/ppc.ad | 194 +- hotspot/src/cpu/ppc/vm/register_ppc.hpp | 6 + hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp | 4 +- hotspot/src/cpu/ppc/vm/runtime_ppc.cpp | 40 +- hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp | 72 +- hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp | 624 +++- .../src/cpu/ppc/vm/stubRoutines_ppc_64.cpp | 2 +- .../cpu/ppc/vm/templateInterpreter_ppc.cpp | 26 +- .../cpu/ppc/vm/templateInterpreter_ppc.hpp | 2 - .../src/cpu/ppc/vm/templateTable_ppc_64.cpp | 32 +- hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp | 40 +- hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp | 3 - hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp | 20 +- hotspot/src/os/aix/vm/c1_globals_aix.hpp | 37 + 50 files changed, 9055 insertions(+), 623 deletions(-) create mode 100644 hotspot/make/aix/makefiles/tiered.make create mode 100644 hotspot/src/cpu/ppc/vm/c1_CodeStubs_ppc.cpp create mode 100644 hotspot/src/cpu/ppc/vm/c1_Defs_ppc.hpp create mode 100644 hotspot/src/cpu/ppc/vm/c1_FpuStackSim_ppc.hpp create mode 100644 hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.cpp create mode 100644 hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.hpp create mode 100644 hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp create mode 100644 hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp create mode 100644 hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp create mode 100644 hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.cpp create mode 100644 hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.hpp create mode 100644 hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp create mode 100644 hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.hpp create mode 100644 hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp create mode 100644 hotspot/src/cpu/ppc/vm/c1_globals_ppc.hpp create mode 100644 hotspot/src/os/aix/vm/c1_globals_aix.hpp diff --git a/hotspot/make/aix/Makefile b/hotspot/make/aix/Makefile index 4e0db05251c..77e54d08dc0 100644 --- a/hotspot/make/aix/Makefile +++ b/hotspot/make/aix/Makefile @@ -1,6 +1,6 @@ # # Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. -# Copyright 2012, 2013 SAP AG. All rights reserved. +# Copyright 2012, 2015 SAP AG. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -61,10 +61,6 @@ ifndef CC_INTERP FORCE_TIERED=1 endif endif -# C1 is not ported on ppc64(le), so we cannot build a tiered VM: -ifneq (,$(filter $(ARCH),ppc64 pp64le)) - FORCE_TIERED=0 -endif ifdef LP64 ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","") diff --git a/hotspot/make/aix/makefiles/fastdebug.make b/hotspot/make/aix/makefiles/fastdebug.make index 33bf50940b9..d7feb025617 100644 --- a/hotspot/make/aix/makefiles/fastdebug.make +++ b/hotspot/make/aix/makefiles/fastdebug.make @@ -68,5 +68,5 @@ MAPFILE = $(GAMMADIR)/make/aix/makefiles/mapfile-vers-debug LFLAGS_QIPA= VERSION = optimized -SYSDEFS += -DASSERT -DFASTDEBUG +SYSDEFS += -DASSERT PICFLAGS = DEFAULT diff --git a/hotspot/make/aix/makefiles/tiered.make b/hotspot/make/aix/makefiles/tiered.make new file mode 100644 index 00000000000..992d59d5241 --- /dev/null +++ b/hotspot/make/aix/makefiles/tiered.make @@ -0,0 +1,32 @@ +# +# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright 2012, 2015 SAP AG. All rights reserved. +# 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. +# +# + +# Sets make macros for making tiered version of VM + +TYPE=TIERED + +VM_SUBDIR = server + +CFLAGS += -DCOMPILER2 -DCOMPILER1 diff --git a/hotspot/make/linux/Makefile b/hotspot/make/linux/Makefile index 52aa0305f7a..dba28625eec 100644 --- a/hotspot/make/linux/Makefile +++ b/hotspot/make/linux/Makefile @@ -57,14 +57,6 @@ ifndef CC_INTERP FORCE_TIERED=1 endif endif -# C1 is not ported on ppc64, so we cannot build a tiered VM: -# Notice: after 8046471 ARCH will be 'ppc' for top-level ppc64 builds but -# 'ppc64' for HotSpot-only ppc64 builds. Need to detect both variants here! -ifneq (,$(findstring $(ARCH), ppc ppc64)) - ifeq ($(ARCH_DATA_MODEL), 64) - FORCE_TIERED=0 - endif -endif ifdef LP64 ifeq ("$(filter $(LP64_ARCH),$(BUILDARCH))","") diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp index 56564ac7ea7..66e4f08c3d4 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.cpp @@ -53,9 +53,6 @@ int AbstractAssembler::code_fill_byte() { return 0x00; // illegal instruction 0x00000000 } -void Assembler::print_instruction(int inst) { - Unimplemented(); -} // Patch instruction `inst' at offset `inst_pos' to refer to // `dest_pos' and return the resulting instruction. We should have @@ -484,7 +481,7 @@ int Assembler::add_const_optimized(Register d, Register s, long x, Register tmp, if (d != s) { mr(d, s); } return 0; } - if (return_simm16_rest) { + if (return_simm16_rest && (d == s)) { return xd; } addi(d, s, xd); diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp index 6c7103aefa4..41cb7a16316 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.hpp @@ -31,10 +31,37 @@ // Address is an abstraction used to represent a memory location // as used in assembler instructions. // PPC instructions grok either baseReg + indexReg or baseReg + disp. -// So far we do not use this as simplification by this class is low -// on PPC with its simple addressing mode. Use RegisterOrConstant to -// represent an offset. class Address VALUE_OBJ_CLASS_SPEC { + private: + Register _base; // Base register. + Register _index; // Index register. + intptr_t _disp; // Displacement. + + public: + Address(Register b, Register i, address d = 0) + : _base(b), _index(i), _disp((intptr_t)d) { + assert(i == noreg || d == 0, "can't have both"); + } + + Address(Register b, address d = 0) + : _base(b), _index(noreg), _disp((intptr_t)d) {} + + Address(Register b, intptr_t d) + : _base(b), _index(noreg), _disp(d) {} + + Address(Register b, RegisterOrConstant roc) + : _base(b), _index(noreg), _disp(0) { + if (roc.is_constant()) _disp = roc.as_constant(); else _index = roc.as_register(); + } + + Address() + : _base(noreg), _index(noreg), _disp(0) {} + + // accessors + Register base() const { return _base; } + Register index() const { return _index; } + int disp() const { return (int)_disp; } + bool is_const() const { return _base == noreg && _index == noreg; } }; class AddressLiteral VALUE_OBJ_CLASS_SPEC { @@ -164,10 +191,14 @@ struct FunctionDescriptor VALUE_OBJ_CLASS_SPEC { }; #endif + +// The PPC Assembler: Pure assembler doing NO optimizations on the +// instruction level; i.e., what you write is what you get. The +// Assembler is generating code into a CodeBuffer. + class Assembler : public AbstractAssembler { protected: // Displacement routines - static void print_instruction(int inst); static int patched_branch(int dest_pos, int inst, int inst_pos); static int branch_destination(int inst, int pos); @@ -839,41 +870,38 @@ class Assembler : public AbstractAssembler { enum Predict { pt = 1, pn = 0 }; // pt = predict taken - // instruction must start at passed address + // Instruction must start at passed address. static int instr_len(unsigned char *instr) { return BytesPerInstWord; } - // instruction must be left-justified in argument - static int instr_len(unsigned long instr) { return BytesPerInstWord; } - // longest instructions static int instr_maxlen() { return BytesPerInstWord; } // Test if x is within signed immediate range for nbits. static bool is_simm(int x, unsigned int nbits) { assert(0 < nbits && nbits < 32, "out of bounds"); - const int min = -( ((int)1) << nbits-1 ); - const int maxplus1 = ( ((int)1) << nbits-1 ); + const int min = -(((int)1) << nbits-1); + const int maxplus1 = (((int)1) << nbits-1); return min <= x && x < maxplus1; } static bool is_simm(jlong x, unsigned int nbits) { assert(0 < nbits && nbits < 64, "out of bounds"); - const jlong min = -( ((jlong)1) << nbits-1 ); - const jlong maxplus1 = ( ((jlong)1) << nbits-1 ); + const jlong min = -(((jlong)1) << nbits-1); + const jlong maxplus1 = (((jlong)1) << nbits-1); return min <= x && x < maxplus1; } - // Test if x is within unsigned immediate range for nbits + // Test if x is within unsigned immediate range for nbits. static bool is_uimm(int x, unsigned int nbits) { assert(0 < nbits && nbits < 32, "out of bounds"); - const int maxplus1 = ( ((int)1) << nbits ); - return 0 <= x && x < maxplus1; + const unsigned int maxplus1 = (((unsigned int)1) << nbits); + return (unsigned int)x < maxplus1; } static bool is_uimm(jlong x, unsigned int nbits) { assert(0 < nbits && nbits < 64, "out of bounds"); - const jlong maxplus1 = ( ((jlong)1) << nbits ); - return 0 <= x && x < maxplus1; + const julong maxplus1 = (((julong)1) << nbits); + return (julong)x < maxplus1; } protected: @@ -1376,8 +1404,11 @@ class Assembler : public AbstractAssembler { inline void orc( Register a, Register s, Register b); inline void orc_( Register a, Register s, Register b); inline void extsb( Register a, Register s); + inline void extsb_( Register a, Register s); inline void extsh( Register a, Register s); + inline void extsh_( Register a, Register s); inline void extsw( Register a, Register s); + inline void extsw_( Register a, Register s); // extended mnemonics inline void nop(); @@ -1767,6 +1798,8 @@ class Assembler : public AbstractAssembler { inline void smt_yield(); inline void smt_mdoio(); inline void smt_mdoom(); + // >= Power8 + inline void smt_miso(); // trap instructions inline void twi_0(Register a); // for load with acquire semantics use load+twi_0+isync (trap can't occur) @@ -2168,6 +2201,7 @@ class Assembler : public AbstractAssembler { inline void load_const(Register d, void* a, Register tmp = noreg); inline void load_const(Register d, Label& L, Register tmp = noreg); inline void load_const(Register d, AddressLiteral& a, Register tmp = noreg); + inline void load_const32(Register d, int i); // load signed int (patchable) // Load a 64 bit constant, optimized, not identifyable. // Tmp can be used to increase ILP. Set return_simm16_rest = true to get a diff --git a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp index e860dac7d43..2a4b03f760b 100644 --- a/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/assembler_ppc.inline.hpp @@ -206,8 +206,11 @@ inline void Assembler::andc_( Register a, Register s, Register b) { emit_in inline void Assembler::orc( Register a, Register s, Register b) { emit_int32(ORC_OPCODE | rta(a) | rs(s) | rb(b) | rc(0)); } inline void Assembler::orc_( Register a, Register s, Register b) { emit_int32(ORC_OPCODE | rta(a) | rs(s) | rb(b) | rc(1)); } inline void Assembler::extsb( Register a, Register s) { emit_int32(EXTSB_OPCODE | rta(a) | rs(s) | rc(0)); } +inline void Assembler::extsb_( Register a, Register s) { emit_int32(EXTSB_OPCODE | rta(a) | rs(s) | rc(1)); } inline void Assembler::extsh( Register a, Register s) { emit_int32(EXTSH_OPCODE | rta(a) | rs(s) | rc(0)); } +inline void Assembler::extsh_( Register a, Register s) { emit_int32(EXTSH_OPCODE | rta(a) | rs(s) | rc(1)); } inline void Assembler::extsw( Register a, Register s) { emit_int32(EXTSW_OPCODE | rta(a) | rs(s) | rc(0)); } +inline void Assembler::extsw_( Register a, Register s) { emit_int32(EXTSW_OPCODE | rta(a) | rs(s) | rc(1)); } // extended mnemonics inline void Assembler::nop() { Assembler::ori(R0, R0, 0); } @@ -609,6 +612,8 @@ inline void Assembler::smt_prio_high() { Assembler::or_unchecked(R3, R3, inline void Assembler::smt_yield() { Assembler::or_unchecked(R27, R27, R27); } inline void Assembler::smt_mdoio() { Assembler::or_unchecked(R29, R29, R29); } inline void Assembler::smt_mdoom() { Assembler::or_unchecked(R30, R30, R30); } +// >= Power8 +inline void Assembler::smt_miso() { Assembler::or_unchecked(R26, R26, R26); } inline void Assembler::twi_0(Register a) { twi_unchecked(0, a, 0);} @@ -967,12 +972,15 @@ inline void Assembler::load_const(Register d, Label& L, Register tmp) { // Load a 64 bit constant encoded by an AddressLiteral. patchable. inline void Assembler::load_const(Register d, AddressLiteral& a, Register tmp) { - assert(d != R0, "R0 not allowed"); // First relocate (we don't change the offset in the RelocationHolder, // just pass a.rspec()), then delegate to load_const(Register, long). relocate(a.rspec()); load_const(d, (long)a.value(), tmp); } +inline void Assembler::load_const32(Register d, int i) { + lis(d, i >> 16); + ori(d, d, i & 0xFFFF); +} #endif // CPU_PPC_VM_ASSEMBLER_PPC_INLINE_HPP diff --git a/hotspot/src/cpu/ppc/vm/c1_CodeStubs_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_CodeStubs_ppc.cpp new file mode 100644 index 00000000000..a19c7b7de11 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_CodeStubs_ppc.cpp @@ -0,0 +1,527 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 "c1/c1_CodeStubs.hpp" +#include "c1/c1_FrameMap.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "nativeInst_ppc.hpp" +#include "runtime/sharedRuntime.hpp" +#include "utilities/macros.hpp" +#include "vmreg_ppc.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc/g1/g1SATBCardTableModRefBS.hpp" +#endif // INCLUDE_ALL_GCS + +#define __ ce->masm()-> + + +RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, + bool throw_index_out_of_bounds_exception) + : _throw_index_out_of_bounds_exception(throw_index_out_of_bounds_exception) + , _index(index) { + assert(info != NULL, "must have info"); + _info = new CodeEmitInfo(info); +} + +void RangeCheckStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + + if (_info->deoptimize_on_exception()) { + address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + // May be used by optimizations like LoopInvariantCodeMotion or RangeCheckEliminator. + DEBUG_ONLY( __ untested("RangeCheckStub: predicate_failed_trap_id"); ) + //__ load_const_optimized(R0, a); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a)); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ illtrap()); + return; + } + + address stub = _throw_index_out_of_bounds_exception ? Runtime1::entry_for(Runtime1::throw_index_exception_id) + : Runtime1::entry_for(Runtime1::throw_range_check_failed_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + + Register index = R0; // pass in R0 + if (_index->is_register()) { + __ extsw(index, _index->as_register()); + } else { + __ load_const_optimized(index, _index->as_jint()); + } + + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ illtrap()); +} + + +PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { + _info = new CodeEmitInfo(info); +} + +void PredicateFailedStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + //__ load_const_optimized(R0, a); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a)); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ illtrap()); +} + + +void CounterOverflowStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + + // Parameter 1: bci + __ load_const_optimized(R0, _bci); + __ std(R0, -16, R1_SP); + + // Parameter 2: Method* + Metadata *m = _method->as_constant_ptr()->as_metadata(); + AddressLiteral md = __ constant_metadata_address(m); // Notify OOP recorder (don't need the relocation). + __ load_const_optimized(R0, md.value()); + __ std(R0, -8, R1_SP); + + address a = Runtime1::entry_for(Runtime1::counter_overflow_id); + //__ load_const_optimized(R0, a); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a)); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + + __ b(_continuation); +} + + +void DivByZeroStub::emit_code(LIR_Assembler* ce) { + if (_offset != -1) { + ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); + } + __ bind(_entry); + address stub = Runtime1::entry_for(Runtime1::throw_div0_exception_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ illtrap()); +} + + +void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { + address a; + if (_info->deoptimize_on_exception()) { + // Deoptimize, do not throw the exception, because it is probably wrong to do it here. + a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + } else { + a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id); + } + + if (ImplicitNullChecks || TrapBasedNullChecks) { + ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); + } + __ bind(_entry); + //__ load_const_optimized(R0, a); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(a)); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ illtrap()); +} + + +// Implementation of SimpleExceptionStub +void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + address stub = Runtime1::entry_for(_stub); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + if (_obj->is_valid()) { __ mr_if_needed(/*tmp1 in do_CheckCast*/ R4_ARG2, _obj->as_register()); } + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + debug_only( __ illtrap(); ) +} + + +// Implementation of NewInstanceStub +NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) { + _result = result; + _klass = klass; + _klass_reg = klass_reg; + _info = new CodeEmitInfo(info); + assert(stub_id == Runtime1::new_instance_id || + stub_id == Runtime1::fast_new_instance_id || + stub_id == Runtime1::fast_new_instance_init_check_id, + "need new_instance id"); + _stub_id = stub_id; +} + +void NewInstanceStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + + address entry = Runtime1::entry_for(_stub_id); + //__ load_const_optimized(R0, entry); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry)); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + __ b(_continuation); +} + + +// Implementation of NewTypeArrayStub +NewTypeArrayStub::NewTypeArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) { + _klass_reg = klass_reg; + _length = length; + _result = result; + _info = new CodeEmitInfo(info); +} + +void NewTypeArrayStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + + address entry = Runtime1::entry_for(Runtime1::new_type_array_id); + //__ load_const_optimized(R0, entry); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry)); + __ mr_if_needed(/*op->tmp1()->as_register()*/ R5_ARG3, _length->as_register()); // already sign-extended + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + __ b(_continuation); +} + + +// Implementation of NewObjectArrayStub +NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) { + _klass_reg = klass_reg; + _length = length; + _result = result; + _info = new CodeEmitInfo(info); +} + +void NewObjectArrayStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + + address entry = Runtime1::entry_for(Runtime1::new_object_array_id); + //__ load_const_optimized(R0, entry); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry)); + __ mr_if_needed(/*op->tmp1()->as_register()*/ R5_ARG3, _length->as_register()); // already sign-extended + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + __ b(_continuation); +} + + +// Implementation of MonitorAccessStubs +MonitorEnterStub::MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info) + : MonitorAccessStub(obj_reg, lock_reg) { + _info = new CodeEmitInfo(info); +} + +void MonitorEnterStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? Runtime1::monitorenter_id : Runtime1::monitorenter_nofpu_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mr_if_needed(/*scratch_opr()->as_register()*/ R4_ARG2, _obj_reg->as_register()); + assert(_lock_reg->as_register() == R5_ARG3, ""); + __ mtctr(R0); + __ bctrl(); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + __ b(_continuation); +} + +void MonitorExitStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + if (_compute_lock) { + ce->monitor_address(_monitor_ix, _lock_reg); + } + address stub = Runtime1::entry_for(ce->compilation()->has_fpu_code() ? Runtime1::monitorexit_id : Runtime1::monitorexit_nofpu_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + assert(_lock_reg->as_register() == R4_ARG2, ""); + __ mtctr(R0); + __ bctrl(); + __ b(_continuation); +} + + +// Implementation of patching: +// - Copy the code at given offset to an inlined buffer (first the bytes, then the number of bytes). +// - Replace original code with a call to the stub. +// At Runtime: +// - call to stub, jump to runtime +// - in runtime: preserve all registers (especially objects, i.e., source and destination object) +// - in runtime: after initializing class, restore original code, reexecute instruction + +int PatchingStub::_patch_info_offset = -(5 * BytesPerInstWord); + +void PatchingStub::align_patch_site(MacroAssembler* ) { + // Patch sites on ppc are always properly aligned. +} + +#ifdef ASSERT +inline void compare_with_patch_site(address template_start, address pc_start, int bytes_to_copy) { + address start = template_start; + for (int i = 0; i < bytes_to_copy; i++) { + address ptr = (address)(pc_start + i); + int a_byte = (*ptr) & 0xFF; + assert(a_byte == *start++, "should be the same code"); + } +} +#endif + +void PatchingStub::emit_code(LIR_Assembler* ce) { + // copy original code here + assert(NativeGeneralJump::instruction_size <= _bytes_to_copy && _bytes_to_copy <= 0xFF, + "not enough room for call"); + assert((_bytes_to_copy & 0x3) == 0, "must copy a multiple of four bytes"); + + Label call_patch; + + int being_initialized_entry = __ offset(); + + if (_id == load_klass_id) { + // Produce a copy of the load klass instruction for use by the being initialized case. + AddressLiteral addrlit((address)NULL, metadata_Relocation::spec(_index)); + __ load_const(_obj, addrlit, R0); + DEBUG_ONLY( compare_with_patch_site(__ code_section()->start() + being_initialized_entry, _pc_start, _bytes_to_copy); ) + } else if (_id == load_mirror_id || _id == load_appendix_id) { + // Produce a copy of the load mirror instruction for use by the being initialized case. + AddressLiteral addrlit((address)NULL, oop_Relocation::spec(_index)); + __ load_const(_obj, addrlit, R0); + DEBUG_ONLY( compare_with_patch_site(__ code_section()->start() + being_initialized_entry, _pc_start, _bytes_to_copy); ) + } else { + // Make a copy the code which is going to be patched. + for (int i = 0; i < _bytes_to_copy; i++) { + address ptr = (address)(_pc_start + i); + int a_byte = (*ptr) & 0xFF; + __ emit_int8 (a_byte); + } + } + + address end_of_patch = __ pc(); + int bytes_to_skip = 0; + if (_id == load_mirror_id) { + int offset = __ offset(); + __ block_comment(" being_initialized check"); + + // Static field accesses have special semantics while the class + // initializer is being run so we emit a test which can be used to + // check that this code is being executed by the initializing + // thread. + assert(_obj != noreg, "must be a valid register"); + assert(_index >= 0, "must have oop index"); + __ mr(R0, _obj); // spill + __ ld(_obj, java_lang_Class::klass_offset_in_bytes(), _obj); + __ ld(_obj, in_bytes(InstanceKlass::init_thread_offset()), _obj); + __ cmpd(CCR0, _obj, R16_thread); + __ mr(_obj, R0); // restore + __ bne(CCR0, call_patch); + + // Load_klass patches may execute the patched code before it's + // copied back into place so we need to jump back into the main + // code of the nmethod to continue execution. + __ b(_patch_site_continuation); + + // Make sure this extra code gets skipped. + bytes_to_skip += __ offset() - offset; + } + + // Now emit the patch record telling the runtime how to find the + // pieces of the patch. We only need 3 bytes but it has to be + // aligned as an instruction so emit 4 bytes. + int sizeof_patch_record = 4; + bytes_to_skip += sizeof_patch_record; + + // Emit the offsets needed to find the code to patch. + int being_initialized_entry_offset = __ offset() - being_initialized_entry + sizeof_patch_record; + + // Emit the patch record. We need to emit a full word, so emit an extra empty byte. + __ emit_int8(0); + __ emit_int8(being_initialized_entry_offset); + __ emit_int8(bytes_to_skip); + __ emit_int8(_bytes_to_copy); + address patch_info_pc = __ pc(); + assert(patch_info_pc - end_of_patch == bytes_to_skip, "incorrect patch info"); + + address entry = __ pc(); + NativeGeneralJump::insert_unconditional((address)_pc_start, entry); + address target = NULL; + relocInfo::relocType reloc_type = relocInfo::none; + switch (_id) { + case access_field_id: target = Runtime1::entry_for(Runtime1::access_field_patching_id); break; + case load_klass_id: target = Runtime1::entry_for(Runtime1::load_klass_patching_id); + reloc_type = relocInfo::metadata_type; break; + case load_mirror_id: target = Runtime1::entry_for(Runtime1::load_mirror_patching_id); + reloc_type = relocInfo::oop_type; break; + case load_appendix_id: target = Runtime1::entry_for(Runtime1::load_appendix_patching_id); + reloc_type = relocInfo::oop_type; break; + default: ShouldNotReachHere(); + } + __ bind(call_patch); + + __ block_comment("patch entry point"); + //__ load_const(R0, target); + mtctr + bctrl must have size -_patch_info_offset + __ load_const32(R0, MacroAssembler::offset_to_global_toc(target)); + __ add(R0, R29_TOC, R0); + __ mtctr(R0); + __ bctrl(); + assert(_patch_info_offset == (patch_info_pc - __ pc()), "must not change"); + ce->add_call_info_here(_info); + __ b(_patch_site_entry); + if (_id == load_klass_id || _id == load_mirror_id || _id == load_appendix_id) { + CodeSection* cs = __ code_section(); + address pc = (address)_pc_start; + RelocIterator iter(cs, pc, pc + 1); + relocInfo::change_reloc_info_for_address(&iter, (address) pc, reloc_type, relocInfo::none); + } +} + + +void DeoptimizeStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + address stub = Runtime1::entry_for(Runtime1::deoptimize_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + + __ load_const_optimized(R0, _trap_request); // Pass trap request in R0. + __ bctrl(); + ce->add_call_info_here(_info); + debug_only(__ illtrap()); +} + + +void ArrayCopyStub::emit_code(LIR_Assembler* ce) { + //---------------slow case: call to native----------------- + __ bind(_entry); + __ mr(R3_ARG1, src()->as_register()); + __ extsw(R4_ARG2, src_pos()->as_register()); + __ mr(R5_ARG3, dst()->as_register()); + __ extsw(R6_ARG4, dst_pos()->as_register()); + __ extsw(R7_ARG5, length()->as_register()); + + ce->emit_static_call_stub(); + + bool success = ce->emit_trampoline_stub_for_call(SharedRuntime::get_resolve_static_call_stub()); + if (!success) { return; } + + __ relocate(relocInfo::static_call_type); + // Note: At this point we do not have the address of the trampoline + // stub, and the entry point might be too far away for bl, so __ pc() + // serves as dummy and the bl will be patched later. + __ code()->set_insts_mark(); + __ bl(__ pc()); + ce->add_call_info_here(info()); + ce->verify_oop_map(info()); + +#ifndef PRODUCT + const address counter = (address)&Runtime1::_arraycopy_slowcase_cnt; + const Register tmp = R3, tmp2 = R4; + int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true); + __ lwz(tmp2, simm16_offs, tmp); + __ addi(tmp2, tmp2, 1); + __ stw(tmp2, simm16_offs, tmp); +#endif + + __ b(_continuation); +} + + +/////////////////////////////////////////////////////////////////////////////////// +#if INCLUDE_ALL_GCS + +void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { + // At this point we know that marking is in progress. + // If do_load() is true then we have to emit the + // load of the previous value; otherwise it has already + // been loaded into _pre_val. + + __ bind(_entry); + + assert(pre_val()->is_register(), "Precondition."); + Register pre_val_reg = pre_val()->as_register(); + + if (do_load()) { + ce->mem2reg(addr(), pre_val(), T_OBJECT, patch_code(), info(), false /*wide*/, false /*unaligned*/); + } + + __ cmpdi(CCR0, pre_val_reg, 0); + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), _continuation); + + address stub = Runtime1::entry_for(Runtime1::Runtime1::g1_pre_barrier_slow_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ std(pre_val_reg, -8, R1_SP); // Pass pre_val on stack. + __ mtctr(R0); + __ bctrl(); + __ b(_continuation); +} + +void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + + assert(addr()->is_register(), "Precondition."); + assert(new_val()->is_register(), "Precondition."); + Register addr_reg = addr()->as_pointer_register(); + Register new_val_reg = new_val()->as_register(); + + __ cmpdi(CCR0, new_val_reg, 0); + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), _continuation); + + address stub = Runtime1::entry_for(Runtime1::Runtime1::g1_post_barrier_slow_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + __ mr(R0, addr_reg); // Pass addr in R0. + __ bctrl(); + __ b(_continuation); +} + +#endif // INCLUDE_ALL_GCS +/////////////////////////////////////////////////////////////////////////////////// + +#undef __ diff --git a/hotspot/src/cpu/ppc/vm/c1_Defs_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_Defs_ppc.hpp new file mode 100644 index 00000000000..73edcaba207 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_Defs_ppc.hpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 CPU_PPC_VM_C1_DEFS_PPC_HPP +#define CPU_PPC_VM_C1_DEFS_PPC_HPP + +// Native word offsets from memory address. +enum { +#if defined(VM_LITTLE_ENDIAN) + pd_lo_word_offset_in_bytes = 0, + pd_hi_word_offset_in_bytes = BytesPerInt +#else + pd_lo_word_offset_in_bytes = BytesPerInt, + pd_hi_word_offset_in_bytes = 0 +#endif +}; + + +// Explicit rounding operations are not required to implement the strictFP mode. +enum { + pd_strict_fp_requires_explicit_rounding = false +}; + + +// registers +enum { + pd_nof_cpu_regs_frame_map = 32, // Number of registers used during code emission. + pd_nof_caller_save_cpu_regs_frame_map = 27, // Number of cpu registers killed by calls. (At least R3_ARG1 ... R10_ARG8, but using all like C2.) + pd_nof_cpu_regs_reg_alloc = 27, // Number of registers that are visible to register allocator. + pd_nof_cpu_regs_linearscan = 32, // Number of registers visible linear scan. + pd_first_callee_saved_reg = pd_nof_caller_save_cpu_regs_frame_map, + pd_last_callee_saved_reg = pd_nof_cpu_regs_reg_alloc - 1, + pd_first_cpu_reg = 0, + pd_last_cpu_reg = pd_nof_cpu_regs_reg_alloc - 1, + + pd_nof_fpu_regs_frame_map = 32, // Number of registers used during code emission. + pd_nof_caller_save_fpu_regs_frame_map = 32, // Number of fpu registers killed by calls. + pd_nof_fpu_regs_reg_alloc = 32, // Number of registers that are visible to register allocator. + pd_nof_fpu_regs_linearscan = 32, // Number of registers visible to linear scan. + pd_first_fpu_reg = pd_nof_cpu_regs_frame_map, + pd_last_fpu_reg = pd_nof_cpu_regs_frame_map + pd_nof_fpu_regs_reg_alloc - 1, + + pd_nof_xmm_regs_linearscan = 0, + pd_nof_caller_save_xmm_regs = 0, + pd_first_xmm_reg = -1, + pd_last_xmm_reg = -1 +}; + +// For debug info: a float value in a register is saved in single precision by runtime stubs. +enum { + pd_float_saved_as_double = true +}; + +#endif // CPU_PPC_VM_C1_DEFS_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c1_FpuStackSim_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_FpuStackSim_ppc.hpp new file mode 100644 index 00000000000..19f85034ba9 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_FpuStackSim_ppc.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 CPU_PPC_VM_C1_FPUSTACKSIM_PPC_HPP +#define CPU_PPC_VM_C1_FPUSTACKSIM_PPC_HPP + +// No FPU stack on PPC. +class FpuStackSim; + +#endif // CPU_PPC_VM_C1_FPUSTACKSIM_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.cpp new file mode 100644 index 00000000000..90afc7873ce --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.cpp @@ -0,0 +1,394 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 "c1/c1_FrameMap.hpp" +#include "c1/c1_LIR.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_ppc.inline.hpp" + + +const int FrameMap::pd_c_runtime_reserved_arg_size = 7; + + +LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool outgoing) { + LIR_Opr opr = LIR_OprFact::illegalOpr; + VMReg r_1 = reg->first(); + VMReg r_2 = reg->second(); + if (r_1->is_stack()) { + // Convert stack slot to an SP offset. + // The calling convention does not count the SharedRuntime::out_preserve_stack_slots() value + // so we must add it in here. + int st_off = (r_1->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size; + opr = LIR_OprFact::address(new LIR_Address(SP_opr, st_off + STACK_BIAS, type)); + } else if (r_1->is_Register()) { + Register reg = r_1->as_Register(); + //if (outgoing) { + // assert(!reg->is_in(), "should be using I regs"); + //} else { + // assert(!reg->is_out(), "should be using O regs"); + //} + if (r_2->is_Register() && (type == T_LONG || type == T_DOUBLE)) { + opr = as_long_opr(reg); + } else if (type == T_OBJECT || type == T_ARRAY) { + opr = as_oop_opr(reg); + } else { + opr = as_opr(reg); + } + } else if (r_1->is_FloatRegister()) { + assert(type == T_DOUBLE || type == T_FLOAT, "wrong type"); + FloatRegister f = r_1->as_FloatRegister(); + if (type == T_DOUBLE) { + opr = as_double_opr(f); + } else { + opr = as_float_opr(f); + } + } + return opr; +} + +// FrameMap +//-------------------------------------------------------- + +FloatRegister FrameMap::_fpu_regs [FrameMap::nof_fpu_regs]; + +LIR_Opr FrameMap::R0_opr; +LIR_Opr FrameMap::R1_opr; +LIR_Opr FrameMap::R2_opr; +LIR_Opr FrameMap::R3_opr; +LIR_Opr FrameMap::R4_opr; +LIR_Opr FrameMap::R5_opr; +LIR_Opr FrameMap::R6_opr; +LIR_Opr FrameMap::R7_opr; +LIR_Opr FrameMap::R8_opr; +LIR_Opr FrameMap::R9_opr; +LIR_Opr FrameMap::R10_opr; +LIR_Opr FrameMap::R11_opr; +LIR_Opr FrameMap::R12_opr; +LIR_Opr FrameMap::R13_opr; +LIR_Opr FrameMap::R14_opr; +LIR_Opr FrameMap::R15_opr; +LIR_Opr FrameMap::R16_opr; +LIR_Opr FrameMap::R17_opr; +LIR_Opr FrameMap::R18_opr; +LIR_Opr FrameMap::R19_opr; +LIR_Opr FrameMap::R20_opr; +LIR_Opr FrameMap::R21_opr; +LIR_Opr FrameMap::R22_opr; +LIR_Opr FrameMap::R23_opr; +LIR_Opr FrameMap::R24_opr; +LIR_Opr FrameMap::R25_opr; +LIR_Opr FrameMap::R26_opr; +LIR_Opr FrameMap::R27_opr; +LIR_Opr FrameMap::R28_opr; +LIR_Opr FrameMap::R29_opr; +LIR_Opr FrameMap::R30_opr; +LIR_Opr FrameMap::R31_opr; + +LIR_Opr FrameMap::R0_oop_opr; +//LIR_Opr FrameMap::R1_oop_opr; +LIR_Opr FrameMap::R2_oop_opr; +LIR_Opr FrameMap::R3_oop_opr; +LIR_Opr FrameMap::R4_oop_opr; +LIR_Opr FrameMap::R5_oop_opr; +LIR_Opr FrameMap::R6_oop_opr; +LIR_Opr FrameMap::R7_oop_opr; +LIR_Opr FrameMap::R8_oop_opr; +LIR_Opr FrameMap::R9_oop_opr; +LIR_Opr FrameMap::R10_oop_opr; +LIR_Opr FrameMap::R11_oop_opr; +LIR_Opr FrameMap::R12_oop_opr; +//LIR_Opr FrameMap::R13_oop_opr; +LIR_Opr FrameMap::R14_oop_opr; +LIR_Opr FrameMap::R15_oop_opr; +//LIR_Opr FrameMap::R16_oop_opr; +LIR_Opr FrameMap::R17_oop_opr; +LIR_Opr FrameMap::R18_oop_opr; +LIR_Opr FrameMap::R19_oop_opr; +LIR_Opr FrameMap::R20_oop_opr; +LIR_Opr FrameMap::R21_oop_opr; +LIR_Opr FrameMap::R22_oop_opr; +LIR_Opr FrameMap::R23_oop_opr; +LIR_Opr FrameMap::R24_oop_opr; +LIR_Opr FrameMap::R25_oop_opr; +LIR_Opr FrameMap::R26_oop_opr; +LIR_Opr FrameMap::R27_oop_opr; +LIR_Opr FrameMap::R28_oop_opr; +//LIR_Opr FrameMap::R29_oop_opr; +LIR_Opr FrameMap::R30_oop_opr; +LIR_Opr FrameMap::R31_oop_opr; + +LIR_Opr FrameMap::R0_metadata_opr; +//LIR_Opr FrameMap::R1_metadata_opr; +LIR_Opr FrameMap::R2_metadata_opr; +LIR_Opr FrameMap::R3_metadata_opr; +LIR_Opr FrameMap::R4_metadata_opr; +LIR_Opr FrameMap::R5_metadata_opr; +LIR_Opr FrameMap::R6_metadata_opr; +LIR_Opr FrameMap::R7_metadata_opr; +LIR_Opr FrameMap::R8_metadata_opr; +LIR_Opr FrameMap::R9_metadata_opr; +LIR_Opr FrameMap::R10_metadata_opr; +LIR_Opr FrameMap::R11_metadata_opr; +LIR_Opr FrameMap::R12_metadata_opr; +//LIR_Opr FrameMap::R13_metadata_opr; +LIR_Opr FrameMap::R14_metadata_opr; +LIR_Opr FrameMap::R15_metadata_opr; +//LIR_Opr FrameMap::R16_metadata_opr; +LIR_Opr FrameMap::R17_metadata_opr; +LIR_Opr FrameMap::R18_metadata_opr; +LIR_Opr FrameMap::R19_metadata_opr; +LIR_Opr FrameMap::R20_metadata_opr; +LIR_Opr FrameMap::R21_metadata_opr; +LIR_Opr FrameMap::R22_metadata_opr; +LIR_Opr FrameMap::R23_metadata_opr; +LIR_Opr FrameMap::R24_metadata_opr; +LIR_Opr FrameMap::R25_metadata_opr; +LIR_Opr FrameMap::R26_metadata_opr; +LIR_Opr FrameMap::R27_metadata_opr; +LIR_Opr FrameMap::R28_metadata_opr; +//LIR_Opr FrameMap::R29_metadata_opr; +LIR_Opr FrameMap::R30_metadata_opr; +LIR_Opr FrameMap::R31_metadata_opr; + +LIR_Opr FrameMap::SP_opr; + +LIR_Opr FrameMap::R0_long_opr; +LIR_Opr FrameMap::R3_long_opr; + +LIR_Opr FrameMap::F1_opr; +LIR_Opr FrameMap::F1_double_opr; + +LIR_Opr FrameMap::_caller_save_cpu_regs[] = { 0, }; +LIR_Opr FrameMap::_caller_save_fpu_regs[] = { 0, }; + +FloatRegister FrameMap::nr2floatreg (int rnr) { + assert(_init_done, "tables not initialized"); + debug_only(fpu_range_check(rnr);) + return _fpu_regs[rnr]; +} + + +// Returns true if reg could be smashed by a callee. +bool FrameMap::is_caller_save_register (LIR_Opr reg) { + if (reg->is_single_fpu() || reg->is_double_fpu()) { return true; } + if (reg->is_double_cpu()) { + return is_caller_save_register(reg->as_register_lo()) || + is_caller_save_register(reg->as_register_hi()); + } + return is_caller_save_register(reg->as_register()); +} + + +bool FrameMap::is_caller_save_register (Register r) { + // not visible to allocator: R0: scratch, R1: SP + // r->encoding() < 2 + nof_caller_save_cpu_regs(); + return true; // Currently all regs are caller save. +} + + +void FrameMap::initialize() { + assert(!_init_done, "once"); + + int i = 0; + + // Put generally available registers at the beginning (allocated, saved for GC). + for (int j = 0; j < nof_cpu_regs; ++j) { + Register rj = as_Register(j); + if (reg_needs_save(rj)) { + map_register(i++, rj); + } + } + assert(i == nof_cpu_regs_reg_alloc, "number of allocated registers"); + + // The following registers are not normally available. + for (int j = 0; j < nof_cpu_regs; ++j) { + Register rj = as_Register(j); + if (!reg_needs_save(rj)) { + map_register(i++, rj); + } + } + assert(i == nof_cpu_regs, "number of CPU registers"); + + for (i = 0; i < nof_fpu_regs; i++) { + _fpu_regs[i] = as_FloatRegister(i); + } + + _init_done = true; + + R0_opr = as_opr(R0); + R1_opr = as_opr(R1); + R2_opr = as_opr(R2); + R3_opr = as_opr(R3); + R4_opr = as_opr(R4); + R5_opr = as_opr(R5); + R6_opr = as_opr(R6); + R7_opr = as_opr(R7); + R8_opr = as_opr(R8); + R9_opr = as_opr(R9); + R10_opr = as_opr(R10); + R11_opr = as_opr(R11); + R12_opr = as_opr(R12); + R13_opr = as_opr(R13); + R14_opr = as_opr(R14); + R15_opr = as_opr(R15); + R16_opr = as_opr(R16); + R17_opr = as_opr(R17); + R18_opr = as_opr(R18); + R19_opr = as_opr(R19); + R20_opr = as_opr(R20); + R21_opr = as_opr(R21); + R22_opr = as_opr(R22); + R23_opr = as_opr(R23); + R24_opr = as_opr(R24); + R25_opr = as_opr(R25); + R26_opr = as_opr(R26); + R27_opr = as_opr(R27); + R28_opr = as_opr(R28); + R29_opr = as_opr(R29); + R30_opr = as_opr(R30); + R31_opr = as_opr(R31); + + R0_oop_opr = as_oop_opr(R0); + //R1_oop_opr = as_oop_opr(R1); + R2_oop_opr = as_oop_opr(R2); + R3_oop_opr = as_oop_opr(R3); + R4_oop_opr = as_oop_opr(R4); + R5_oop_opr = as_oop_opr(R5); + R6_oop_opr = as_oop_opr(R6); + R7_oop_opr = as_oop_opr(R7); + R8_oop_opr = as_oop_opr(R8); + R9_oop_opr = as_oop_opr(R9); + R10_oop_opr = as_oop_opr(R10); + R11_oop_opr = as_oop_opr(R11); + R12_oop_opr = as_oop_opr(R12); + //R13_oop_opr = as_oop_opr(R13); + R14_oop_opr = as_oop_opr(R14); + R15_oop_opr = as_oop_opr(R15); + //R16_oop_opr = as_oop_opr(R16); + R17_oop_opr = as_oop_opr(R17); + R18_oop_opr = as_oop_opr(R18); + R19_oop_opr = as_oop_opr(R19); + R20_oop_opr = as_oop_opr(R20); + R21_oop_opr = as_oop_opr(R21); + R22_oop_opr = as_oop_opr(R22); + R23_oop_opr = as_oop_opr(R23); + R24_oop_opr = as_oop_opr(R24); + R25_oop_opr = as_oop_opr(R25); + R26_oop_opr = as_oop_opr(R26); + R27_oop_opr = as_oop_opr(R27); + R28_oop_opr = as_oop_opr(R28); + //R29_oop_opr = as_oop_opr(R29); + R30_oop_opr = as_oop_opr(R30); + R31_oop_opr = as_oop_opr(R31); + + R0_metadata_opr = as_metadata_opr(R0); + //R1_metadata_opr = as_metadata_opr(R1); + R2_metadata_opr = as_metadata_opr(R2); + R3_metadata_opr = as_metadata_opr(R3); + R4_metadata_opr = as_metadata_opr(R4); + R5_metadata_opr = as_metadata_opr(R5); + R6_metadata_opr = as_metadata_opr(R6); + R7_metadata_opr = as_metadata_opr(R7); + R8_metadata_opr = as_metadata_opr(R8); + R9_metadata_opr = as_metadata_opr(R9); + R10_metadata_opr = as_metadata_opr(R10); + R11_metadata_opr = as_metadata_opr(R11); + R12_metadata_opr = as_metadata_opr(R12); + //R13_metadata_opr = as_metadata_opr(R13); + R14_metadata_opr = as_metadata_opr(R14); + R15_metadata_opr = as_metadata_opr(R15); + //R16_metadata_opr = as_metadata_opr(R16); + R17_metadata_opr = as_metadata_opr(R17); + R18_metadata_opr = as_metadata_opr(R18); + R19_metadata_opr = as_metadata_opr(R19); + R20_metadata_opr = as_metadata_opr(R20); + R21_metadata_opr = as_metadata_opr(R21); + R22_metadata_opr = as_metadata_opr(R22); + R23_metadata_opr = as_metadata_opr(R23); + R24_metadata_opr = as_metadata_opr(R24); + R25_metadata_opr = as_metadata_opr(R25); + R26_metadata_opr = as_metadata_opr(R26); + R27_metadata_opr = as_metadata_opr(R27); + R28_metadata_opr = as_metadata_opr(R28); + //R29_metadata_opr = as_metadata_opr(R29); + R30_metadata_opr = as_metadata_opr(R30); + R31_metadata_opr = as_metadata_opr(R31); + + SP_opr = as_pointer_opr(R1_SP); + + R0_long_opr = LIR_OprFact::double_cpu(cpu_reg2rnr(R0), cpu_reg2rnr(R0)); + R3_long_opr = LIR_OprFact::double_cpu(cpu_reg2rnr(R3), cpu_reg2rnr(R3)); + + F1_opr = as_float_opr(F1); + F1_double_opr = as_double_opr(F1); + + // All the allocated cpu regs are caller saved. + for (int i = 0; i < max_nof_caller_save_cpu_regs; i++) { + _caller_save_cpu_regs[i] = LIR_OprFact::single_cpu(i); + } + + // All the fpu regs are caller saved. + for (int i = 0; i < nof_caller_save_fpu_regs; i++) { + _caller_save_fpu_regs[i] = LIR_OprFact::single_fpu(i); + } +} + + +Address FrameMap::make_new_address(ByteSize sp_offset) const { + return Address(R1_SP, STACK_BIAS + in_bytes(sp_offset)); +} + + +VMReg FrameMap::fpu_regname (int n) { + return as_FloatRegister(n)->as_VMReg(); +} + + +LIR_Opr FrameMap::stack_pointer() { + return SP_opr; +} + + +// JSR 292 +// On PPC64, there is no need to save the SP, because neither +// method handle intrinsics, nor compiled lambda forms modify it. +LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { + return LIR_OprFact::illegalOpr; +} + + +bool FrameMap::validate_frame() { + int max_offset = in_bytes(framesize_in_bytes()); + int java_index = 0; + for (int i = 0; i < _incoming_arguments->length(); i++) { + LIR_Opr opr = _incoming_arguments->at(i); + if (opr->is_stack()) { + max_offset = MAX2(_argument_locations->at(java_index), max_offset); + } + java_index += type2size[opr->type()]; + } + return Assembler::is_simm16(max_offset + STACK_BIAS); +} diff --git a/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.hpp new file mode 100644 index 00000000000..5eee5ffca1f --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_FrameMap_ppc.hpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 CPU_PPC_VM_C1_FRAMEMAP_PPC_HPP +#define CPU_PPC_VM_C1_FRAMEMAP_PPC_HPP + + public: + + enum { + nof_reg_args = 8, // Registers R3-R10 are available for parameter passing. + first_available_sp_in_frame = frame::jit_out_preserve_size, + frame_pad_in_bytes = 0 + }; + + static const int pd_c_runtime_reserved_arg_size; + + static LIR_Opr R0_opr; + static LIR_Opr R1_opr; + static LIR_Opr R2_opr; + static LIR_Opr R3_opr; + static LIR_Opr R4_opr; + static LIR_Opr R5_opr; + static LIR_Opr R6_opr; + static LIR_Opr R7_opr; + static LIR_Opr R8_opr; + static LIR_Opr R9_opr; + static LIR_Opr R10_opr; + static LIR_Opr R11_opr; + static LIR_Opr R12_opr; + static LIR_Opr R13_opr; + static LIR_Opr R14_opr; + static LIR_Opr R15_opr; + static LIR_Opr R16_opr; + static LIR_Opr R17_opr; + static LIR_Opr R18_opr; + static LIR_Opr R19_opr; + static LIR_Opr R20_opr; + static LIR_Opr R21_opr; + static LIR_Opr R22_opr; + static LIR_Opr R23_opr; + static LIR_Opr R24_opr; + static LIR_Opr R25_opr; + static LIR_Opr R26_opr; + static LIR_Opr R27_opr; + static LIR_Opr R28_opr; + static LIR_Opr R29_opr; + static LIR_Opr R30_opr; + static LIR_Opr R31_opr; + + static LIR_Opr R0_oop_opr; + //R1: Stack pointer. Not an oop. + static LIR_Opr R2_oop_opr; + static LIR_Opr R3_oop_opr; + static LIR_Opr R4_oop_opr; + static LIR_Opr R5_oop_opr; + static LIR_Opr R6_oop_opr; + static LIR_Opr R7_oop_opr; + static LIR_Opr R8_oop_opr; + static LIR_Opr R9_oop_opr; + static LIR_Opr R10_oop_opr; + static LIR_Opr R11_oop_opr; + static LIR_Opr R12_oop_opr; + //R13: System thread register. Not usable. + static LIR_Opr R14_oop_opr; + static LIR_Opr R15_oop_opr; + //R16: Java thread register. Not an oop. + static LIR_Opr R17_oop_opr; + static LIR_Opr R18_oop_opr; + static LIR_Opr R19_oop_opr; + static LIR_Opr R20_oop_opr; + static LIR_Opr R21_oop_opr; + static LIR_Opr R22_oop_opr; + static LIR_Opr R23_oop_opr; + static LIR_Opr R24_oop_opr; + static LIR_Opr R25_oop_opr; + static LIR_Opr R26_oop_opr; + static LIR_Opr R27_oop_opr; + static LIR_Opr R28_oop_opr; + static LIR_Opr R29_oop_opr; + //R29: TOC register. Not an oop. + static LIR_Opr R30_oop_opr; + static LIR_Opr R31_oop_opr; + + static LIR_Opr R0_metadata_opr; + //R1: Stack pointer. Not metadata. + static LIR_Opr R2_metadata_opr; + static LIR_Opr R3_metadata_opr; + static LIR_Opr R4_metadata_opr; + static LIR_Opr R5_metadata_opr; + static LIR_Opr R6_metadata_opr; + static LIR_Opr R7_metadata_opr; + static LIR_Opr R8_metadata_opr; + static LIR_Opr R9_metadata_opr; + static LIR_Opr R10_metadata_opr; + static LIR_Opr R11_metadata_opr; + static LIR_Opr R12_metadata_opr; + //R13: System thread register. Not usable. + static LIR_Opr R14_metadata_opr; + static LIR_Opr R15_metadata_opr; + //R16: Java thread register. Not metadata. + static LIR_Opr R17_metadata_opr; + static LIR_Opr R18_metadata_opr; + static LIR_Opr R19_metadata_opr; + static LIR_Opr R20_metadata_opr; + static LIR_Opr R21_metadata_opr; + static LIR_Opr R22_metadata_opr; + static LIR_Opr R23_metadata_opr; + static LIR_Opr R24_metadata_opr; + static LIR_Opr R25_metadata_opr; + static LIR_Opr R26_metadata_opr; + static LIR_Opr R27_metadata_opr; + static LIR_Opr R28_metadata_opr; + //R29: TOC register. Not metadata. + static LIR_Opr R30_metadata_opr; + static LIR_Opr R31_metadata_opr; + + static LIR_Opr SP_opr; + + static LIR_Opr R0_long_opr; + static LIR_Opr R3_long_opr; + + static LIR_Opr F1_opr; + static LIR_Opr F1_double_opr; + + private: + static FloatRegister _fpu_regs [nof_fpu_regs]; + + static LIR_Opr as_long_single_opr(Register r) { + return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); + } + static LIR_Opr as_long_pair_opr(Register r) { + return LIR_OprFact::double_cpu(cpu_reg2rnr(r->successor()), cpu_reg2rnr(r)); + } + + public: + +#ifdef _LP64 + static LIR_Opr as_long_opr(Register r) { + return as_long_single_opr(r); + } + static LIR_Opr as_pointer_opr(Register r) { + return as_long_single_opr(r); + } +#else + static LIR_Opr as_long_opr(Register r) { + Unimplemented(); return 0; +// return as_long_pair_opr(r); + } + static LIR_Opr as_pointer_opr(Register r) { + Unimplemented(); return 0; +// return as_opr(r); + } +#endif + static LIR_Opr as_float_opr(FloatRegister r) { + return LIR_OprFact::single_fpu(r->encoding()); + } + static LIR_Opr as_double_opr(FloatRegister r) { + return LIR_OprFact::double_fpu(r->encoding()); + } + + static FloatRegister nr2floatreg (int rnr); + + static VMReg fpu_regname (int n); + + static bool is_caller_save_register(LIR_Opr reg); + static bool is_caller_save_register(Register r); + + static int nof_caller_save_cpu_regs() { return pd_nof_caller_save_cpu_regs_frame_map; } + static int last_cpu_reg() { return pd_last_cpu_reg; } + + // Registers which need to be saved in the frames (e.g. for GC). + // Register usage: + // R0: scratch + // R1: sp + // R13: system thread id + // R16: java thread + // R29: global TOC + static bool reg_needs_save(Register r) { return r != R0 && r != R1 && r != R13 && r != R16 && r != R29; } + +#endif // CPU_PPC_VM_C1_FRAMEMAP_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp new file mode 100644 index 00000000000..8a64bab4be4 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp @@ -0,0 +1,3133 @@ +/* + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 "c1/c1_Compilation.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "c1/c1_ValueStack.hpp" +#include "ci/ciArrayKlass.hpp" +#include "ci/ciInstance.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/cardTableModRefBS.hpp" +#include "nativeInst_ppc.hpp" +#include "oops/objArrayKlass.hpp" +#include "runtime/sharedRuntime.hpp" + +#define __ _masm-> + + +const ConditionRegister LIR_Assembler::BOOL_RESULT = CCR5; + + +bool LIR_Assembler::is_small_constant(LIR_Opr opr) { + Unimplemented(); return false; // Currently not used on this platform. +} + + +LIR_Opr LIR_Assembler::receiverOpr() { + return FrameMap::R3_oop_opr; +} + + +LIR_Opr LIR_Assembler::osrBufferPointer() { + return FrameMap::R3_opr; +} + + +// This specifies the stack pointer decrement needed to build the frame. +int LIR_Assembler::initial_frame_size_in_bytes() const { + return in_bytes(frame_map()->framesize_in_bytes()); +} + + +// Inline cache check: the inline cached class is in inline_cache_reg; +// we fetch the class of the receiver and compare it with the cached class. +// If they do not match we jump to slow case. +int LIR_Assembler::check_icache() { + int offset = __ offset(); + __ inline_cache_check(R3_ARG1, R19_inline_cache_reg); + return offset; +} + + +void LIR_Assembler::osr_entry() { + // On-stack-replacement entry sequence: + // + // 1. Create a new compiled activation. + // 2. Initialize local variables in the compiled activation. The expression + // stack must be empty at the osr_bci; it is not initialized. + // 3. Jump to the continuation address in compiled code to resume execution. + + // OSR entry point + offsets()->set_value(CodeOffsets::OSR_Entry, code_offset()); + BlockBegin* osr_entry = compilation()->hir()->osr_entry(); + ValueStack* entry_state = osr_entry->end()->state(); + int number_of_locks = entry_state->locks_size(); + + // Create a frame for the compiled activation. + __ build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes()); + + // OSR buffer is + // + // locals[nlocals-1..0] + // monitors[number_of_locks-1..0] + // + // Locals is a direct copy of the interpreter frame so in the osr buffer + // the first slot in the local array is the last local from the interpreter + // and the last slot is local[0] (receiver) from the interpreter. + // + // Similarly with locks. The first lock slot in the osr buffer is the nth lock + // from the interpreter frame, the nth lock slot in the osr buffer is 0th lock + // in the interpreter frame (the method lock if a sync method). + + // Initialize monitors in the compiled activation. + // R3: pointer to osr buffer + // + // All other registers are dead at this point and the locals will be + // copied into place by code emitted in the IR. + + Register OSR_buf = osrBufferPointer()->as_register(); + { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); + int monitor_offset = BytesPerWord * method()->max_locals() + + (2 * BytesPerWord) * (number_of_locks - 1); + // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in + // the OSR buffer using 2 word entries: first the lock and then + // the oop. + for (int i = 0; i < number_of_locks; i++) { + int slot_offset = monitor_offset - ((i * 2) * BytesPerWord); +#ifdef ASSERT + // Verify the interpreter's monitor has a non-null object. + { + Label L; + __ ld(R0, slot_offset + 1*BytesPerWord, OSR_buf); + __ cmpdi(CCR0, R0, 0); + __ bne(CCR0, L); + __ stop("locked object is NULL"); + __ bind(L); + } +#endif // ASSERT + // Copy the lock field into the compiled activation. + Address ml = frame_map()->address_for_monitor_lock(i), + mo = frame_map()->address_for_monitor_object(i); + assert(ml.index() == noreg && mo.index() == noreg, "sanity"); + __ ld(R0, slot_offset + 0, OSR_buf); + __ std(R0, ml.disp(), ml.base()); + __ ld(R0, slot_offset + 1*BytesPerWord, OSR_buf); + __ std(R0, mo.disp(), mo.base()); + } + } +} + + +int LIR_Assembler::emit_exception_handler() { + // If the last instruction is a call (typically to do a throw which + // is coming at the end after block reordering) the return address + // must still point into the code area in order to avoid assertion + // failures when searching for the corresponding bci => add a nop + // (was bug 5/14/1999 - gri). + __ nop(); + + // Generate code for the exception handler. + address handler_base = __ start_a_stub(exception_handler_size); + + if (handler_base == NULL) { + // Not enough space left for the handler. + bailout("exception handler overflow"); + return -1; + } + + int offset = code_offset(); + address entry_point = CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::handle_exception_from_callee_id)); + //__ load_const_optimized(R0, entry_point); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(entry_point)); + __ mtctr(R0); + __ bctr(); + + guarantee(code_offset() - offset <= exception_handler_size, "overflow"); + __ end_a_stub(); + + return offset; +} + + +// Emit the code to remove the frame from the stack in the exception +// unwind path. +int LIR_Assembler::emit_unwind_handler() { + _masm->block_comment("Unwind handler"); + + int offset = code_offset(); + bool preserve_exception = method()->is_synchronized() || compilation()->env()->dtrace_method_probes(); + const Register Rexception = R3 /*LIRGenerator::exceptionOopOpr()*/, Rexception_save = R31; + + // Fetch the exception from TLS and clear out exception related thread state. + __ ld(Rexception, in_bytes(JavaThread::exception_oop_offset()), R16_thread); + __ li(R0, 0); + __ std(R0, in_bytes(JavaThread::exception_oop_offset()), R16_thread); + __ std(R0, in_bytes(JavaThread::exception_pc_offset()), R16_thread); + + __ bind(_unwind_handler_entry); + __ verify_not_null_oop(Rexception); + if (preserve_exception) { __ mr(Rexception_save, Rexception); } + + // Perform needed unlocking + MonitorExitStub* stub = NULL; + if (method()->is_synchronized()) { + monitor_address(0, FrameMap::R4_opr); + stub = new MonitorExitStub(FrameMap::R4_opr, true, 0); + __ unlock_object(R5, R6, R4, *stub->entry()); + __ bind(*stub->continuation()); + } + + if (compilation()->env()->dtrace_method_probes()) { + Unimplemented(); + } + + // Dispatch to the unwind logic. + address unwind_stub = Runtime1::entry_for(Runtime1::unwind_exception_id); + //__ load_const_optimized(R0, unwind_stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(unwind_stub)); + if (preserve_exception) { __ mr(Rexception, Rexception_save); } + __ mtctr(R0); + __ bctr(); + + // Emit the slow path assembly. + if (stub != NULL) { + stub->emit_code(this); + } + + return offset; +} + + +int LIR_Assembler::emit_deopt_handler() { + // If the last instruction is a call (typically to do a throw which + // is coming at the end after block reordering) the return address + // must still point into the code area in order to avoid assertion + // failures when searching for the corresponding bci => add a nop + // (was bug 5/14/1999 - gri). + __ nop(); + + // Generate code for deopt handler. + address handler_base = __ start_a_stub(deopt_handler_size); + + if (handler_base == NULL) { + // Not enough space left for the handler. + bailout("deopt handler overflow"); + return -1; + } + + int offset = code_offset(); + __ bl64_patchable(SharedRuntime::deopt_blob()->unpack(), relocInfo::runtime_call_type); + + guarantee(code_offset() - offset <= deopt_handler_size, "overflow"); + __ end_a_stub(); + + return offset; +} + + +void LIR_Assembler::jobject2reg(jobject o, Register reg) { + if (o == NULL) { + __ li(reg, 0); + } else { + AddressLiteral addrlit = __ constant_oop_address(o); + __ load_const(reg, addrlit, (reg != R0) ? R0 : noreg); + } +} + + +void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo *info) { + // Allocate a new index in table to hold the object once it's been patched. + int oop_index = __ oop_recorder()->allocate_oop_index(NULL); + PatchingStub* patch = new PatchingStub(_masm, patching_id(info), oop_index); + + AddressLiteral addrlit((address)NULL, oop_Relocation::spec(oop_index)); + __ load_const(reg, addrlit, R0); + + patching_epilog(patch, lir_patch_normal, reg, info); +} + + +void LIR_Assembler::metadata2reg(Metadata* o, Register reg) { + AddressLiteral md = __ constant_metadata_address(o); // Notify OOP recorder (don't need the relocation) + __ load_const_optimized(reg, md.value(), (reg != R0) ? R0 : noreg); +} + + +void LIR_Assembler::klass2reg_with_patching(Register reg, CodeEmitInfo *info) { + // Allocate a new index in table to hold the klass once it's been patched. + int index = __ oop_recorder()->allocate_metadata_index(NULL); + PatchingStub* patch = new PatchingStub(_masm, PatchingStub::load_klass_id, index); + + AddressLiteral addrlit((address)NULL, metadata_Relocation::spec(index)); + assert(addrlit.rspec().type() == relocInfo::metadata_type, "must be an metadata reloc"); + __ load_const(reg, addrlit, R0); + + patching_epilog(patch, lir_patch_normal, reg, info); +} + + +void LIR_Assembler::emit_op3(LIR_Op3* op) { + const bool is_int = op->result_opr()->is_single_cpu(); + Register Rdividend = is_int ? op->in_opr1()->as_register() : op->in_opr1()->as_register_lo(); + Register Rdivisor = noreg; + Register Rscratch = op->in_opr3()->as_register(); + Register Rresult = is_int ? op->result_opr()->as_register() : op->result_opr()->as_register_lo(); + long divisor = -1; + + if (op->in_opr2()->is_register()) { + Rdivisor = is_int ? op->in_opr2()->as_register() : op->in_opr2()->as_register_lo(); + } else { + divisor = is_int ? op->in_opr2()->as_constant_ptr()->as_jint() + : op->in_opr2()->as_constant_ptr()->as_jlong(); + } + + assert(Rdividend != Rscratch, ""); + assert(Rdivisor != Rscratch, ""); + assert(op->code() == lir_idiv || op->code() == lir_irem, "Must be irem or idiv"); + + if (Rdivisor == noreg) { + if (divisor == 1) { // stupid, but can happen + if (op->code() == lir_idiv) { + __ mr_if_needed(Rresult, Rdividend); + } else { + __ li(Rresult, 0); + } + + } else if (is_power_of_2(divisor)) { + // Convert division by a power of two into some shifts and logical operations. + int log2 = log2_intptr(divisor); + + // Round towards 0. + if (divisor == 2) { + if (is_int) { + __ srwi(Rscratch, Rdividend, 31); + } else { + __ srdi(Rscratch, Rdividend, 63); + } + } else { + if (is_int) { + __ srawi(Rscratch, Rdividend, 31); + } else { + __ sradi(Rscratch, Rdividend, 63); + } + __ clrldi(Rscratch, Rscratch, 64-log2); + } + __ add(Rscratch, Rdividend, Rscratch); + + if (op->code() == lir_idiv) { + if (is_int) { + __ srawi(Rresult, Rscratch, log2); + } else { + __ sradi(Rresult, Rscratch, log2); + } + } else { // lir_irem + __ clrrdi(Rscratch, Rscratch, log2); + __ sub(Rresult, Rdividend, Rscratch); + } + + } else if (divisor == -1) { + if (op->code() == lir_idiv) { + __ neg(Rresult, Rdividend); + } else { + __ li(Rresult, 0); + } + + } else { + __ load_const_optimized(Rscratch, divisor); + if (op->code() == lir_idiv) { + if (is_int) { + __ divw(Rresult, Rdividend, Rscratch); // Can't divide minint/-1. + } else { + __ divd(Rresult, Rdividend, Rscratch); // Can't divide minint/-1. + } + } else { + assert(Rscratch != R0, "need both"); + if (is_int) { + __ divw(R0, Rdividend, Rscratch); // Can't divide minint/-1. + __ mullw(Rscratch, R0, Rscratch); + } else { + __ divd(R0, Rdividend, Rscratch); // Can't divide minint/-1. + __ mulld(Rscratch, R0, Rscratch); + } + __ sub(Rresult, Rdividend, Rscratch); + } + + } + return; + } + + Label regular, done; + if (is_int) { + __ cmpwi(CCR0, Rdivisor, -1); + } else { + __ cmpdi(CCR0, Rdivisor, -1); + } + __ bne(CCR0, regular); + if (op->code() == lir_idiv) { + __ neg(Rresult, Rdividend); + __ b(done); + __ bind(regular); + if (is_int) { + __ divw(Rresult, Rdividend, Rdivisor); // Can't divide minint/-1. + } else { + __ divd(Rresult, Rdividend, Rdivisor); // Can't divide minint/-1. + } + } else { // lir_irem + __ li(Rresult, 0); + __ b(done); + __ bind(regular); + if (is_int) { + __ divw(Rscratch, Rdividend, Rdivisor); // Can't divide minint/-1. + __ mullw(Rscratch, Rscratch, Rdivisor); + } else { + __ divd(Rscratch, Rdividend, Rdivisor); // Can't divide minint/-1. + __ mulld(Rscratch, Rscratch, Rdivisor); + } + __ sub(Rresult, Rdividend, Rscratch); + } + __ bind(done); +} + + +void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) { +#ifdef ASSERT + assert(op->block() == NULL || op->block()->label() == op->label(), "wrong label"); + if (op->block() != NULL) _branch_target_blocks.append(op->block()); + if (op->ublock() != NULL) _branch_target_blocks.append(op->ublock()); + assert(op->info() == NULL, "shouldn't have CodeEmitInfo"); +#endif + + Label *L = op->label(); + if (op->cond() == lir_cond_always) { + __ b(*L); + } else { + Label done; + bool is_unordered = false; + if (op->code() == lir_cond_float_branch) { + assert(op->ublock() != NULL, "must have unordered successor"); + is_unordered = true; + } else { + assert(op->code() == lir_branch, "just checking"); + } + + bool positive = false; + Assembler::Condition cond = Assembler::equal; + switch (op->cond()) { + case lir_cond_equal: positive = true ; cond = Assembler::equal ; is_unordered = false; break; + case lir_cond_notEqual: positive = false; cond = Assembler::equal ; is_unordered = false; break; + case lir_cond_less: positive = true ; cond = Assembler::less ; break; + case lir_cond_belowEqual: assert(op->code() != lir_cond_float_branch, ""); // fallthru + case lir_cond_lessEqual: positive = false; cond = Assembler::greater; break; + case lir_cond_greater: positive = true ; cond = Assembler::greater; break; + case lir_cond_aboveEqual: assert(op->code() != lir_cond_float_branch, ""); // fallthru + case lir_cond_greaterEqual: positive = false; cond = Assembler::less ; break; + default: ShouldNotReachHere(); + } + int bo = positive ? Assembler::bcondCRbiIs1 : Assembler::bcondCRbiIs0; + int bi = Assembler::bi0(BOOL_RESULT, cond); + if (is_unordered) { + if (positive) { + if (op->ublock() == op->block()) { + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(BOOL_RESULT, Assembler::summary_overflow), *L); + } + } else { + if (op->ublock() != op->block()) { __ bso(BOOL_RESULT, done); } + } + } + __ bc_far_optimized(bo, bi, *L); + __ bind(done); + } +} + + +void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { + Bytecodes::Code code = op->bytecode(); + LIR_Opr src = op->in_opr(), + dst = op->result_opr(); + + switch(code) { + case Bytecodes::_i2l: { + __ extsw(dst->as_register_lo(), src->as_register()); + break; + } + case Bytecodes::_l2i: { + __ mr_if_needed(dst->as_register(), src->as_register_lo()); // high bits are garbage + break; + } + case Bytecodes::_i2b: { + __ extsb(dst->as_register(), src->as_register()); + break; + } + case Bytecodes::_i2c: { + __ clrldi(dst->as_register(), src->as_register(), 64-16); + break; + } + case Bytecodes::_i2s: { + __ extsh(dst->as_register(), src->as_register()); + break; + } + case Bytecodes::_i2d: + case Bytecodes::_l2d: { + __ fcfid(dst->as_double_reg(), src->as_double_reg()); // via mem + break; + } + case Bytecodes::_i2f: { + FloatRegister rdst = dst->as_float_reg(); + FloatRegister rsrc = src->as_double_reg(); // via mem + if (VM_Version::has_fcfids()) { + __ fcfids(rdst, rsrc); + } else { + __ fcfid(rdst, rsrc); + __ frsp(rdst, rdst); + } + break; + } + case Bytecodes::_l2f: { // >= Power7 + assert(VM_Version::has_fcfids(), "fcfid+frsp needs fixup code to avoid rounding incompatibility"); + __ fcfids(dst->as_float_reg(), src->as_double_reg()); // via mem + break; + } + case Bytecodes::_f2d: { + __ fmr_if_needed(dst->as_double_reg(), src->as_float_reg()); + break; + } + case Bytecodes::_d2f: { + __ frsp(dst->as_float_reg(), src->as_double_reg()); + break; + } + case Bytecodes::_d2i: + case Bytecodes::_f2i: { + FloatRegister rsrc = (code == Bytecodes::_d2i) ? src->as_double_reg() : src->as_float_reg(); + Address addr = frame_map()->address_for_slot(dst->double_stack_ix()); + Label L; + // Result must be 0 if value is NaN; test by comparing value to itself. + __ fcmpu(CCR0, rsrc, rsrc); + __ li(R0, 0); // 0 in case of NAN + __ std(R0, addr.disp(), addr.base()); + __ bso(CCR0, L); + __ fctiwz(rsrc, rsrc); // USE_KILL + __ stfd(rsrc, addr.disp(), addr.base()); + __ bind(L); + break; + } + case Bytecodes::_d2l: + case Bytecodes::_f2l: { + FloatRegister rsrc = (code == Bytecodes::_d2l) ? src->as_double_reg() : src->as_float_reg(); + Address addr = frame_map()->address_for_slot(dst->double_stack_ix()); + Label L; + // Result must be 0 if value is NaN; test by comparing value to itself. + __ fcmpu(CCR0, rsrc, rsrc); + __ li(R0, 0); // 0 in case of NAN + __ std(R0, addr.disp(), addr.base()); + __ bso(CCR0, L); + __ fctidz(rsrc, rsrc); // USE_KILL + __ stfd(rsrc, addr.disp(), addr.base()); + __ bind(L); + break; + } + + default: ShouldNotReachHere(); + } +} + + +void LIR_Assembler::align_call(LIR_Code) { + // do nothing since all instructions are word aligned on ppc +} + + +bool LIR_Assembler::emit_trampoline_stub_for_call(address target, Register Rtoc) { + int start_offset = __ offset(); + // Put the entry point as a constant into the constant pool. + const address entry_point_toc_addr = __ address_constant(target, RelocationHolder::none); + if (entry_point_toc_addr == NULL) { + bailout("const section overflow"); + return false; + } + const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); + + // Emit the trampoline stub which will be related to the branch-and-link below. + address stub = __ emit_trampoline_stub(entry_point_toc_offset, start_offset, Rtoc); + if (!stub) { + bailout("no space for trampoline stub"); + return false; + } + return true; +} + + +void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { + assert(rtype==relocInfo::opt_virtual_call_type || rtype==relocInfo::static_call_type, "unexpected rtype"); + + bool success = emit_trampoline_stub_for_call(op->addr()); + if (!success) { return; } + + __ relocate(rtype); + // Note: At this point we do not have the address of the trampoline + // stub, and the entry point might be too far away for bl, so __ pc() + // serves as dummy and the bl will be patched later. + __ code()->set_insts_mark(); + __ bl(__ pc()); + add_call_info(code_offset(), op->info()); +} + + +void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { + __ calculate_address_from_global_toc(R2_TOC, __ method_toc()); + + // Virtual call relocation will point to ic load. + address virtual_call_meta_addr = __ pc(); + // Load a clear inline cache. + AddressLiteral empty_ic((address) Universe::non_oop_word()); + bool success = __ load_const_from_method_toc(R19_inline_cache_reg, empty_ic, R2_TOC); + if (!success) { + bailout("const section overflow"); + return; + } + // Call to fixup routine. Fixup routine uses ScopeDesc info + // to determine who we intended to call. + __ relocate(virtual_call_Relocation::spec(virtual_call_meta_addr)); + + success = emit_trampoline_stub_for_call(op->addr(), R2_TOC); + if (!success) { return; } + + // Note: At this point we do not have the address of the trampoline + // stub, and the entry point might be too far away for bl, so __ pc() + // serves as dummy and the bl will be patched later. + __ bl(__ pc()); + add_call_info(code_offset(), op->info()); +} + + +void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) { + ShouldNotReachHere(); // ic_call is used instead. +} + + +void LIR_Assembler::explicit_null_check(Register addr, CodeEmitInfo* info) { + ImplicitNullCheckStub* stub = new ImplicitNullCheckStub(code_offset(), info); + __ null_check(addr, stub->entry()); + append_code_stub(stub); +} + + +// Attention: caller must encode oop if needed +int LIR_Assembler::store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned) { + int store_offset; + if (!Assembler::is_simm16(offset)) { + // For offsets larger than a simm16 we setup the offset. + assert(wide && !from_reg->is_same_register(FrameMap::R0_opr), "large offset only supported in special case"); + __ load_const_optimized(R0, offset); + store_offset = store(from_reg, base, R0, type, wide); + } else { + store_offset = code_offset(); + switch (type) { + case T_BOOLEAN: // fall through + case T_BYTE : __ stb(from_reg->as_register(), offset, base); break; + case T_CHAR : + case T_SHORT : __ sth(from_reg->as_register(), offset, base); break; + case T_INT : __ stw(from_reg->as_register(), offset, base); break; + case T_LONG : __ std(from_reg->as_register_lo(), offset, base); break; + case T_ADDRESS: + case T_METADATA: __ std(from_reg->as_register(), offset, base); break; + case T_ARRAY : // fall through + case T_OBJECT: + { + if (UseCompressedOops && !wide) { + // Encoding done in caller + __ stw(from_reg->as_register(), offset, base); + } else { + __ std(from_reg->as_register(), offset, base); + } + __ verify_oop(from_reg->as_register()); + break; + } + case T_FLOAT : __ stfs(from_reg->as_float_reg(), offset, base); break; + case T_DOUBLE: __ stfd(from_reg->as_double_reg(), offset, base); break; + default : ShouldNotReachHere(); + } + } + return store_offset; +} + + +// Attention: caller must encode oop if needed +int LIR_Assembler::store(LIR_Opr from_reg, Register base, Register disp, BasicType type, bool wide) { + int store_offset = code_offset(); + switch (type) { + case T_BOOLEAN: // fall through + case T_BYTE : __ stbx(from_reg->as_register(), base, disp); break; + case T_CHAR : + case T_SHORT : __ sthx(from_reg->as_register(), base, disp); break; + case T_INT : __ stwx(from_reg->as_register(), base, disp); break; + case T_LONG : +#ifdef _LP64 + __ stdx(from_reg->as_register_lo(), base, disp); +#else + Unimplemented(); +#endif + break; + case T_ADDRESS: + __ stdx(from_reg->as_register(), base, disp); + break; + case T_ARRAY : // fall through + case T_OBJECT: + { + if (UseCompressedOops && !wide) { + // Encoding done in caller. + __ stwx(from_reg->as_register(), base, disp); + } else { + __ stdx(from_reg->as_register(), base, disp); + } + __ verify_oop(from_reg->as_register()); // kills R0 + break; + } + case T_FLOAT : __ stfsx(from_reg->as_float_reg(), base, disp); break; + case T_DOUBLE: __ stfdx(from_reg->as_double_reg(), base, disp); break; + default : ShouldNotReachHere(); + } + return store_offset; +} + + +int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType type, bool wide, bool unaligned) { + int load_offset; + if (!Assembler::is_simm16(offset)) { + // For offsets larger than a simm16 we setup the offset. + __ load_const_optimized(R0, offset); + load_offset = load(base, R0, to_reg, type, wide); + } else { + load_offset = code_offset(); + switch(type) { + case T_BOOLEAN: // fall through + case T_BYTE : __ lbz(to_reg->as_register(), offset, base); + __ extsb(to_reg->as_register(), to_reg->as_register()); break; + case T_CHAR : __ lhz(to_reg->as_register(), offset, base); break; + case T_SHORT : __ lha(to_reg->as_register(), offset, base); break; + case T_INT : __ lwa(to_reg->as_register(), offset, base); break; + case T_LONG : __ ld(to_reg->as_register_lo(), offset, base); break; + case T_METADATA: __ ld(to_reg->as_register(), offset, base); break; + case T_ADDRESS: + if (offset == oopDesc::klass_offset_in_bytes() && UseCompressedClassPointers) { + __ lwz(to_reg->as_register(), offset, base); + __ decode_klass_not_null(to_reg->as_register()); + } else { + __ ld(to_reg->as_register(), offset, base); + } + break; + case T_ARRAY : // fall through + case T_OBJECT: + { + if (UseCompressedOops && !wide) { + __ lwz(to_reg->as_register(), offset, base); + __ decode_heap_oop(to_reg->as_register()); + } else { + __ ld(to_reg->as_register(), offset, base); + } + __ verify_oop(to_reg->as_register()); + break; + } + case T_FLOAT: __ lfs(to_reg->as_float_reg(), offset, base); break; + case T_DOUBLE: __ lfd(to_reg->as_double_reg(), offset, base); break; + default : ShouldNotReachHere(); + } + } + return load_offset; +} + + +int LIR_Assembler::load(Register base, Register disp, LIR_Opr to_reg, BasicType type, bool wide) { + int load_offset = code_offset(); + switch(type) { + case T_BOOLEAN: // fall through + case T_BYTE : __ lbzx(to_reg->as_register(), base, disp); + __ extsb(to_reg->as_register(), to_reg->as_register()); break; + case T_CHAR : __ lhzx(to_reg->as_register(), base, disp); break; + case T_SHORT : __ lhax(to_reg->as_register(), base, disp); break; + case T_INT : __ lwax(to_reg->as_register(), base, disp); break; + case T_ADDRESS: __ ldx(to_reg->as_register(), base, disp); break; + case T_ARRAY : // fall through + case T_OBJECT: + { + if (UseCompressedOops && !wide) { + __ lwzx(to_reg->as_register(), base, disp); + __ decode_heap_oop(to_reg->as_register()); + } else { + __ ldx(to_reg->as_register(), base, disp); + } + __ verify_oop(to_reg->as_register()); + break; + } + case T_FLOAT: __ lfsx(to_reg->as_float_reg() , base, disp); break; + case T_DOUBLE: __ lfdx(to_reg->as_double_reg(), base, disp); break; + case T_LONG : +#ifdef _LP64 + __ ldx(to_reg->as_register_lo(), base, disp); +#else + Unimplemented(); +#endif + break; + default : ShouldNotReachHere(); + } + return load_offset; +} + + +void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) { + LIR_Const* c = src->as_constant_ptr(); + Register src_reg = R0; + switch (c->type()) { + case T_INT: + case T_FLOAT: { + int value = c->as_jint_bits(); + __ load_const_optimized(src_reg, value); + Address addr = frame_map()->address_for_slot(dest->single_stack_ix()); + __ stw(src_reg, addr.disp(), addr.base()); + break; + } + case T_ADDRESS: { + int value = c->as_jint_bits(); + __ load_const_optimized(src_reg, value); + Address addr = frame_map()->address_for_slot(dest->single_stack_ix()); + __ std(src_reg, addr.disp(), addr.base()); + break; + } + case T_OBJECT: { + jobject2reg(c->as_jobject(), src_reg); + Address addr = frame_map()->address_for_slot(dest->single_stack_ix()); + __ std(src_reg, addr.disp(), addr.base()); + break; + } + case T_LONG: + case T_DOUBLE: { + int value = c->as_jlong_bits(); + __ load_const_optimized(src_reg, value); + Address addr = frame_map()->address_for_double_slot(dest->double_stack_ix()); + __ std(src_reg, addr.disp(), addr.base()); + break; + } + default: + Unimplemented(); + } +} + + +void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info, bool wide) { + LIR_Const* c = src->as_constant_ptr(); + LIR_Address* addr = dest->as_address_ptr(); + Register base = addr->base()->as_pointer_register(); + LIR_Opr tmp = LIR_OprFact::illegalOpr; + int offset = -1; + // Null check for large offsets in LIRGenerator::do_StoreField. + bool needs_explicit_null_check = !ImplicitNullChecks; + + if (info != NULL && needs_explicit_null_check) { + explicit_null_check(base, info); + } + + switch (c->type()) { + case T_FLOAT: type = T_INT; + case T_INT: + case T_ADDRESS: { + tmp = FrameMap::R0_opr; + __ load_const_optimized(tmp->as_register(), c->as_jint_bits()); + break; + } + case T_DOUBLE: type = T_LONG; + case T_LONG: { + tmp = FrameMap::R0_long_opr; + __ load_const_optimized(tmp->as_register_lo(), c->as_jlong_bits()); + break; + } + case T_OBJECT: { + tmp = FrameMap::R0_opr; + if (UseCompressedOops && !wide && c->as_jobject() != NULL) { + AddressLiteral oop_addr = __ constant_oop_address(c->as_jobject()); + __ lis(R0, oop_addr.value() >> 16); // Don't care about sign extend (will use stw). + __ relocate(oop_addr.rspec(), /*compressed format*/ 1); + __ ori(R0, R0, oop_addr.value() & 0xffff); + } else { + jobject2reg(c->as_jobject(), R0); + } + break; + } + default: + Unimplemented(); + } + + // Handle either reg+reg or reg+disp address. + if (addr->index()->is_valid()) { + assert(addr->disp() == 0, "must be zero"); + offset = store(tmp, base, addr->index()->as_pointer_register(), type, wide); + } else { + assert(Assembler::is_simm16(addr->disp()), "can't handle larger addresses"); + offset = store(tmp, base, addr->disp(), type, wide, false); + } + + if (info != NULL) { + assert(offset != -1, "offset should've been set"); + if (!needs_explicit_null_check) { + add_debug_info_for_null_check(offset, info); + } + } +} + + +void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) { + LIR_Const* c = src->as_constant_ptr(); + LIR_Opr to_reg = dest; + + switch (c->type()) { + case T_INT: { + assert(patch_code == lir_patch_none, "no patching handled here"); + __ load_const_optimized(dest->as_register(), c->as_jint(), R0); + break; + } + case T_ADDRESS: { + assert(patch_code == lir_patch_none, "no patching handled here"); + __ load_const_optimized(dest->as_register(), c->as_jint(), R0); // Yes, as_jint ... + break; + } + case T_LONG: { + assert(patch_code == lir_patch_none, "no patching handled here"); + __ load_const_optimized(dest->as_register_lo(), c->as_jlong(), R0); + break; + } + + case T_OBJECT: { + if (patch_code == lir_patch_none) { + jobject2reg(c->as_jobject(), to_reg->as_register()); + } else { + jobject2reg_with_patching(to_reg->as_register(), info); + } + break; + } + + case T_METADATA: + { + if (patch_code == lir_patch_none) { + metadata2reg(c->as_metadata(), to_reg->as_register()); + } else { + klass2reg_with_patching(to_reg->as_register(), info); + } + } + break; + + case T_FLOAT: + { + if (to_reg->is_single_fpu()) { + address const_addr = __ float_constant(c->as_jfloat()); + if (const_addr == NULL) { + bailout("const section overflow"); + break; + } + RelocationHolder rspec = internal_word_Relocation::spec(const_addr); + __ relocate(rspec); + __ load_const(R0, const_addr); + __ lfsx(to_reg->as_float_reg(), R0); + } else { + assert(to_reg->is_single_cpu(), "Must be a cpu register."); + __ load_const_optimized(to_reg->as_register(), jint_cast(c->as_jfloat()), R0); + } + } + break; + + case T_DOUBLE: + { + if (to_reg->is_double_fpu()) { + address const_addr = __ double_constant(c->as_jdouble()); + if (const_addr == NULL) { + bailout("const section overflow"); + break; + } + RelocationHolder rspec = internal_word_Relocation::spec(const_addr); + __ relocate(rspec); + __ load_const(R0, const_addr); + __ lfdx(to_reg->as_double_reg(), R0); + } else { + assert(to_reg->is_double_cpu(), "Must be a long register."); + __ load_const_optimized(to_reg->as_register_lo(), jlong_cast(c->as_jdouble()), R0); + } + } + break; + + default: + ShouldNotReachHere(); + } +} + + +Address LIR_Assembler::as_Address(LIR_Address* addr) { + Unimplemented(); return Address(); +} + + +inline RegisterOrConstant index_or_disp(LIR_Address* addr) { + if (addr->index()->is_illegal()) { + return (RegisterOrConstant)(addr->disp()); + } else { + return (RegisterOrConstant)(addr->index()->as_pointer_register()); + } +} + + +void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) { + const Register tmp = R0; + switch (type) { + case T_INT: + case T_FLOAT: { + Address from = frame_map()->address_for_slot(src->single_stack_ix()); + Address to = frame_map()->address_for_slot(dest->single_stack_ix()); + __ lwz(tmp, from.disp(), from.base()); + __ stw(tmp, to.disp(), to.base()); + break; + } + case T_ADDRESS: + case T_OBJECT: { + Address from = frame_map()->address_for_slot(src->single_stack_ix()); + Address to = frame_map()->address_for_slot(dest->single_stack_ix()); + __ ld(tmp, from.disp(), from.base()); + __ std(tmp, to.disp(), to.base()); + break; + } + case T_LONG: + case T_DOUBLE: { + Address from = frame_map()->address_for_double_slot(src->double_stack_ix()); + Address to = frame_map()->address_for_double_slot(dest->double_stack_ix()); + __ ld(tmp, from.disp(), from.base()); + __ std(tmp, to.disp(), to.base()); + break; + } + + default: + ShouldNotReachHere(); + } +} + + +Address LIR_Assembler::as_Address_hi(LIR_Address* addr) { + Unimplemented(); return Address(); +} + + +Address LIR_Assembler::as_Address_lo(LIR_Address* addr) { + Unimplemented(); return Address(); +} + + +void LIR_Assembler::mem2reg(LIR_Opr src_opr, LIR_Opr dest, BasicType type, + LIR_PatchCode patch_code, CodeEmitInfo* info, bool wide, bool unaligned) { + + assert(type != T_METADATA, "load of metadata ptr not supported"); + LIR_Address* addr = src_opr->as_address_ptr(); + LIR_Opr to_reg = dest; + + Register src = addr->base()->as_pointer_register(); + Register disp_reg = noreg; + int disp_value = addr->disp(); + bool needs_patching = (patch_code != lir_patch_none); + // null check for large offsets in LIRGenerator::do_LoadField + bool needs_explicit_null_check = !os::zero_page_read_protected() || !ImplicitNullChecks; + + if (info != NULL && needs_explicit_null_check) { + explicit_null_check(src, info); + } + + if (addr->base()->type() == T_OBJECT) { + __ verify_oop(src); + } + + PatchingStub* patch = NULL; + if (needs_patching) { + patch = new PatchingStub(_masm, PatchingStub::access_field_id); + assert(!to_reg->is_double_cpu() || + patch_code == lir_patch_none || + patch_code == lir_patch_normal, "patching doesn't match register"); + } + + if (addr->index()->is_illegal()) { + if (!Assembler::is_simm16(disp_value)) { + if (needs_patching) { + __ load_const32(R0, 0); // patchable int + } else { + __ load_const_optimized(R0, disp_value); + } + disp_reg = R0; + } + } else { + disp_reg = addr->index()->as_pointer_register(); + assert(disp_value == 0, "can't handle 3 operand addresses"); + } + + // Remember the offset of the load. The patching_epilog must be done + // before the call to add_debug_info, otherwise the PcDescs don't get + // entered in increasing order. + int offset; + + if (disp_reg == noreg) { + assert(Assembler::is_simm16(disp_value), "should have set this up"); + offset = load(src, disp_value, to_reg, type, wide, unaligned); + } else { + assert(!unaligned, "unexpected"); + offset = load(src, disp_reg, to_reg, type, wide); + } + + if (patch != NULL) { + patching_epilog(patch, patch_code, src, info); + } + if (info != NULL && !needs_explicit_null_check) { + add_debug_info_for_null_check(offset, info); + } +} + + +void LIR_Assembler::stack2reg(LIR_Opr src, LIR_Opr dest, BasicType type) { + Address addr; + if (src->is_single_word()) { + addr = frame_map()->address_for_slot(src->single_stack_ix()); + } else if (src->is_double_word()) { + addr = frame_map()->address_for_double_slot(src->double_stack_ix()); + } + + bool unaligned = (addr.disp() - STACK_BIAS) % 8 != 0; + load(addr.base(), addr.disp(), dest, dest->type(), true /*wide*/, unaligned); +} + + +void LIR_Assembler::reg2stack(LIR_Opr from_reg, LIR_Opr dest, BasicType type, bool pop_fpu_stack) { + Address addr; + if (dest->is_single_word()) { + addr = frame_map()->address_for_slot(dest->single_stack_ix()); + } else if (dest->is_double_word()) { + addr = frame_map()->address_for_slot(dest->double_stack_ix()); + } + bool unaligned = (addr.disp() - STACK_BIAS) % 8 != 0; + store(from_reg, addr.base(), addr.disp(), from_reg->type(), true /*wide*/, unaligned); +} + + +void LIR_Assembler::reg2reg(LIR_Opr from_reg, LIR_Opr to_reg) { + if (from_reg->is_float_kind() && to_reg->is_float_kind()) { + if (from_reg->is_double_fpu()) { + // double to double moves + assert(to_reg->is_double_fpu(), "should match"); + __ fmr_if_needed(to_reg->as_double_reg(), from_reg->as_double_reg()); + } else { + // float to float moves + assert(to_reg->is_single_fpu(), "should match"); + __ fmr_if_needed(to_reg->as_float_reg(), from_reg->as_float_reg()); + } + } else if (!from_reg->is_float_kind() && !to_reg->is_float_kind()) { + if (from_reg->is_double_cpu()) { + __ mr_if_needed(to_reg->as_pointer_register(), from_reg->as_pointer_register()); + } else if (to_reg->is_double_cpu()) { + // int to int moves + __ mr_if_needed(to_reg->as_register_lo(), from_reg->as_register()); + } else { + // int to int moves + __ mr_if_needed(to_reg->as_register(), from_reg->as_register()); + } + } else { + ShouldNotReachHere(); + } + if (to_reg->type() == T_OBJECT || to_reg->type() == T_ARRAY) { + __ verify_oop(to_reg->as_register()); + } +} + + +void LIR_Assembler::reg2mem(LIR_Opr from_reg, LIR_Opr dest, BasicType type, + LIR_PatchCode patch_code, CodeEmitInfo* info, bool pop_fpu_stack, + bool wide, bool unaligned) { + assert(type != T_METADATA, "store of metadata ptr not supported"); + LIR_Address* addr = dest->as_address_ptr(); + + Register src = addr->base()->as_pointer_register(); + Register disp_reg = noreg; + int disp_value = addr->disp(); + bool needs_patching = (patch_code != lir_patch_none); + bool compress_oop = (type == T_ARRAY || type == T_OBJECT) && UseCompressedOops && !wide && + Universe::narrow_oop_mode() != Universe::UnscaledNarrowOop; + bool load_disp = addr->index()->is_illegal() && !Assembler::is_simm16(disp_value); + bool use_R29 = compress_oop && load_disp; // Avoid register conflict, also do null check before killing R29. + // Null check for large offsets in LIRGenerator::do_StoreField. + bool needs_explicit_null_check = !ImplicitNullChecks || use_R29; + + if (info != NULL && needs_explicit_null_check) { + explicit_null_check(src, info); + } + + if (addr->base()->is_oop_register()) { + __ verify_oop(src); + } + + PatchingStub* patch = NULL; + if (needs_patching) { + patch = new PatchingStub(_masm, PatchingStub::access_field_id); + assert(!from_reg->is_double_cpu() || + patch_code == lir_patch_none || + patch_code == lir_patch_normal, "patching doesn't match register"); + } + + if (addr->index()->is_illegal()) { + if (load_disp) { + disp_reg = use_R29 ? R29_TOC : R0; + if (needs_patching) { + __ load_const32(disp_reg, 0); // patchable int + } else { + __ load_const_optimized(disp_reg, disp_value); + } + } + } else { + disp_reg = addr->index()->as_pointer_register(); + assert(disp_value == 0, "can't handle 3 operand addresses"); + } + + // remember the offset of the store. The patching_epilog must be done + // before the call to add_debug_info_for_null_check, otherwise the PcDescs don't get + // entered in increasing order. + int offset; + + if (compress_oop) { + Register co = __ encode_heap_oop(R0, from_reg->as_register()); + from_reg = FrameMap::as_opr(co); + } + + if (disp_reg == noreg) { + assert(Assembler::is_simm16(disp_value), "should have set this up"); + offset = store(from_reg, src, disp_value, type, wide, unaligned); + } else { + assert(!unaligned, "unexpected"); + offset = store(from_reg, src, disp_reg, type, wide); + } + + if (use_R29) { + __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R0); // reinit + } + + if (patch != NULL) { + patching_epilog(patch, patch_code, src, info); + } + + if (info != NULL && !needs_explicit_null_check) { + add_debug_info_for_null_check(offset, info); + } +} + + +void LIR_Assembler::return_op(LIR_Opr result) { + const Register return_pc = R11; + const Register polling_page = R12; + + // Pop the stack before the safepoint code. + int frame_size = initial_frame_size_in_bytes(); + if (Assembler::is_simm(frame_size, 16)) { + __ addi(R1_SP, R1_SP, frame_size); + } else { + __ pop_frame(); + } + + if (LoadPollAddressFromThread) { + // TODO: PPC port __ ld(polling_page, in_bytes(JavaThread::poll_address_offset()), R16_thread); + Unimplemented(); + } else { + __ load_const_optimized(polling_page, (long)(address) os::get_polling_page(), R0); // TODO: PPC port: get_standard_polling_page() + } + + // Restore return pc relative to callers' sp. + __ ld(return_pc, _abi(lr), R1_SP); + // Move return pc to LR. + __ mtlr(return_pc); + + // We need to mark the code position where the load from the safepoint + // polling page was emitted as relocInfo::poll_return_type here. + __ relocate(relocInfo::poll_return_type); + __ load_from_polling_page(polling_page); + + // Return. + __ blr(); +} + + +int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { + + if (LoadPollAddressFromThread) { + const Register poll_addr = tmp->as_register(); + // TODO: PPC port __ ld(poll_addr, in_bytes(JavaThread::poll_address_offset()), R16_thread); + Unimplemented(); + __ relocate(relocInfo::poll_type); // XXX + guarantee(info != NULL, "Shouldn't be NULL"); + int offset = __ offset(); + add_debug_info_for_branch(info); + __ load_from_polling_page(poll_addr); + return offset; + } + + __ load_const_optimized(tmp->as_register(), (intptr_t)os::get_polling_page(), R0); // TODO: PPC port: get_standard_polling_page() + if (info != NULL) { + add_debug_info_for_branch(info); + } + int offset = __ offset(); + __ relocate(relocInfo::poll_type); + __ load_from_polling_page(tmp->as_register()); + + return offset; +} + + +void LIR_Assembler::emit_static_call_stub() { + address call_pc = __ pc(); + address stub = __ start_a_stub(max_static_call_stub_size); + if (stub == NULL) { + bailout("static call stub overflow"); + return; + } + + // For java_to_interp stubs we use R11_scratch1 as scratch register + // and in call trampoline stubs we use R12_scratch2. This way we + // can distinguish them (see is_NativeCallTrampolineStub_at()). + const Register reg_scratch = R11_scratch1; + + // Create a static stub relocation which relates this stub + // with the call instruction at insts_call_instruction_offset in the + // instructions code-section. + int start = __ offset(); + __ relocate(static_stub_Relocation::spec(call_pc)); + + // Now, create the stub's code: + // - load the TOC + // - load the inline cache oop from the constant pool + // - load the call target from the constant pool + // - call + __ calculate_address_from_global_toc(reg_scratch, __ method_toc()); + AddressLiteral ic = __ allocate_metadata_address((Metadata *)NULL); + bool success = __ load_const_from_method_toc(R19_inline_cache_reg, ic, reg_scratch, /*fixed_size*/ true); + + if (ReoptimizeCallSequences) { + __ b64_patchable((address)-1, relocInfo::none); + } else { + AddressLiteral a((address)-1); + success = success && __ load_const_from_method_toc(reg_scratch, a, reg_scratch, /*fixed_size*/ true); + __ mtctr(reg_scratch); + __ bctr(); + } + if (!success) { + bailout("const section overflow"); + return; + } + + assert(__ offset() - start <= max_static_call_stub_size, "stub too big"); + __ end_a_stub(); +} + + +void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Op2* op) { + bool unsigned_comp = (condition == lir_cond_belowEqual || condition == lir_cond_aboveEqual); + if (opr1->is_single_fpu()) { + __ fcmpu(BOOL_RESULT, opr1->as_float_reg(), opr2->as_float_reg()); + } else if (opr1->is_double_fpu()) { + __ fcmpu(BOOL_RESULT, opr1->as_double_reg(), opr2->as_double_reg()); + } else if (opr1->is_single_cpu()) { + if (opr2->is_constant()) { + switch (opr2->as_constant_ptr()->type()) { + case T_INT: + { + jint con = opr2->as_constant_ptr()->as_jint(); + if (unsigned_comp) { + if (Assembler::is_uimm(con, 16)) { + __ cmplwi(BOOL_RESULT, opr1->as_register(), con); + } else { + __ load_const_optimized(R0, con); + __ cmplw(BOOL_RESULT, opr1->as_register(), R0); + } + } else { + if (Assembler::is_simm(con, 16)) { + __ cmpwi(BOOL_RESULT, opr1->as_register(), con); + } else { + __ load_const_optimized(R0, con); + __ cmpw(BOOL_RESULT, opr1->as_register(), R0); + } + } + } + break; + + case T_OBJECT: + // There are only equal/notequal comparisons on objects. + { + assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "oops"); + jobject con = opr2->as_constant_ptr()->as_jobject(); + if (con == NULL) { + __ cmpdi(BOOL_RESULT, opr1->as_register(), 0); + } else { + jobject2reg(con, R0); + __ cmpd(BOOL_RESULT, opr1->as_register(), R0); + } + } + break; + + default: + ShouldNotReachHere(); + break; + } + } else { + if (opr2->is_address()) { + DEBUG_ONLY( Unimplemented(); ) // Seems to be unused at the moment. + LIR_Address *addr = opr2->as_address_ptr(); + BasicType type = addr->type(); + if (type == T_OBJECT) { __ ld(R0, index_or_disp(addr), addr->base()->as_register()); } + else { __ lwa(R0, index_or_disp(addr), addr->base()->as_register()); } + __ cmpd(BOOL_RESULT, opr1->as_register(), R0); + } else { + if (unsigned_comp) { + __ cmplw(BOOL_RESULT, opr1->as_register(), opr2->as_register()); + } else { + __ cmpw(BOOL_RESULT, opr1->as_register(), opr2->as_register()); + } + } + } + } else if (opr1->is_double_cpu()) { + if (opr2->is_constant()) { + jlong con = opr2->as_constant_ptr()->as_jlong(); + if (unsigned_comp) { + if (Assembler::is_uimm(con, 16)) { + __ cmpldi(BOOL_RESULT, opr1->as_register_lo(), con); + } else { + __ load_const_optimized(R0, con); + __ cmpld(BOOL_RESULT, opr1->as_register_lo(), R0); + } + } else { + if (Assembler::is_simm(con, 16)) { + __ cmpdi(BOOL_RESULT, opr1->as_register_lo(), con); + } else { + __ load_const_optimized(R0, con); + __ cmpd(BOOL_RESULT, opr1->as_register_lo(), R0); + } + } + } else if (opr2->is_register()) { + if (unsigned_comp) { + __ cmpld(BOOL_RESULT, opr1->as_register_lo(), opr2->as_register_lo()); + } else { + __ cmpd(BOOL_RESULT, opr1->as_register_lo(), opr2->as_register_lo()); + } + } else { + ShouldNotReachHere(); + } + } else if (opr1->is_address()) { + DEBUG_ONLY( Unimplemented(); ) // Seems to be unused at the moment. + LIR_Address * addr = opr1->as_address_ptr(); + BasicType type = addr->type(); + assert (opr2->is_constant(), "Checking"); + if (type == T_OBJECT) { __ ld(R0, index_or_disp(addr), addr->base()->as_register()); } + else { __ lwa(R0, index_or_disp(addr), addr->base()->as_register()); } + __ cmpdi(BOOL_RESULT, R0, opr2->as_constant_ptr()->as_jint()); + } else { + ShouldNotReachHere(); + } +} + + +void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dst, LIR_Op2* op){ + const Register Rdst = dst->as_register(); + Label done; + if (code == lir_cmp_fd2i || code == lir_ucmp_fd2i) { + bool is_unordered_less = (code == lir_ucmp_fd2i); + if (left->is_single_fpu()) { + __ fcmpu(CCR0, left->as_float_reg(), right->as_float_reg()); + } else if (left->is_double_fpu()) { + __ fcmpu(CCR0, left->as_double_reg(), right->as_double_reg()); + } else { + ShouldNotReachHere(); + } + __ li(Rdst, is_unordered_less ? -1 : 1); + __ bso(CCR0, done); + } else if (code == lir_cmp_l2i) { + __ cmpd(CCR0, left->as_register_lo(), right->as_register_lo()); + } else { + ShouldNotReachHere(); + } + __ mfcr(R0); // set bit 32..33 as follows: <: 0b10, =: 0b00, >: 0b01 + __ srwi(Rdst, R0, 30); + __ srawi(R0, R0, 31); + __ orr(Rdst, R0, Rdst); // set result as follows: <: -1, =: 0, >: 1 + __ bind(done); +} + + +inline void load_to_reg(LIR_Assembler *lasm, LIR_Opr src, LIR_Opr dst) { + if (src->is_constant()) { + lasm->const2reg(src, dst, lir_patch_none, NULL); + } else if (src->is_register()) { + lasm->reg2reg(src, dst); + } else if (src->is_stack()) { + lasm->stack2reg(src, dst, dst->type()); + } else { + ShouldNotReachHere(); + } +} + + +void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { + if (opr1->is_equal(opr2) || opr1->is_same_register(opr2)) { + load_to_reg(this, opr1, result); // Condition doesn't matter. + return; + } + + bool positive = false; + Assembler::Condition cond = Assembler::equal; + switch (condition) { + case lir_cond_equal: positive = true ; cond = Assembler::equal ; break; + case lir_cond_notEqual: positive = false; cond = Assembler::equal ; break; + case lir_cond_less: positive = true ; cond = Assembler::less ; break; + case lir_cond_belowEqual: + case lir_cond_lessEqual: positive = false; cond = Assembler::greater; break; + case lir_cond_greater: positive = true ; cond = Assembler::greater; break; + case lir_cond_aboveEqual: + case lir_cond_greaterEqual: positive = false; cond = Assembler::less ; break; + default: ShouldNotReachHere(); + } + + // Try to use isel on >=Power7. + if (VM_Version::has_isel() && result->is_cpu_register()) { + bool o1_is_reg = opr1->is_cpu_register(), o2_is_reg = opr2->is_cpu_register(); + const Register result_reg = result->is_single_cpu() ? result->as_register() : result->as_register_lo(); + + // We can use result_reg to load one operand if not already in register. + Register first = o1_is_reg ? (opr1->is_single_cpu() ? opr1->as_register() : opr1->as_register_lo()) : result_reg, + second = o2_is_reg ? (opr2->is_single_cpu() ? opr2->as_register() : opr2->as_register_lo()) : result_reg; + + if (first != second) { + if (!o1_is_reg) { + load_to_reg(this, opr1, result); + } + + if (!o2_is_reg) { + load_to_reg(this, opr2, result); + } + + __ isel(result_reg, BOOL_RESULT, cond, !positive, first, second); + return; + } + } // isel + + load_to_reg(this, opr1, result); + + Label skip; + int bo = positive ? Assembler::bcondCRbiIs1 : Assembler::bcondCRbiIs0; + int bi = Assembler::bi0(BOOL_RESULT, cond); + __ bc(bo, bi, skip); + + load_to_reg(this, opr2, result); + __ bind(skip); +} + + +void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, + CodeEmitInfo* info, bool pop_fpu_stack) { + assert(info == NULL, "unused on this code path"); + assert(left->is_register(), "wrong items state"); + assert(dest->is_register(), "wrong items state"); + + if (right->is_register()) { + if (dest->is_float_kind()) { + + FloatRegister lreg, rreg, res; + if (right->is_single_fpu()) { + lreg = left->as_float_reg(); + rreg = right->as_float_reg(); + res = dest->as_float_reg(); + switch (code) { + case lir_add: __ fadds(res, lreg, rreg); break; + case lir_sub: __ fsubs(res, lreg, rreg); break; + case lir_mul: // fall through + case lir_mul_strictfp: __ fmuls(res, lreg, rreg); break; + case lir_div: // fall through + case lir_div_strictfp: __ fdivs(res, lreg, rreg); break; + default: ShouldNotReachHere(); + } + } else { + lreg = left->as_double_reg(); + rreg = right->as_double_reg(); + res = dest->as_double_reg(); + switch (code) { + case lir_add: __ fadd(res, lreg, rreg); break; + case lir_sub: __ fsub(res, lreg, rreg); break; + case lir_mul: // fall through + case lir_mul_strictfp: __ fmul(res, lreg, rreg); break; + case lir_div: // fall through + case lir_div_strictfp: __ fdiv(res, lreg, rreg); break; + default: ShouldNotReachHere(); + } + } + + } else if (dest->is_double_cpu()) { + + Register dst_lo = dest->as_register_lo(); + Register op1_lo = left->as_pointer_register(); + Register op2_lo = right->as_pointer_register(); + + switch (code) { + case lir_add: __ add(dst_lo, op1_lo, op2_lo); break; + case lir_sub: __ sub(dst_lo, op1_lo, op2_lo); break; + case lir_mul: __ mulld(dst_lo, op1_lo, op2_lo); break; + default: ShouldNotReachHere(); + } + } else { + assert (right->is_single_cpu(), "Just Checking"); + + Register lreg = left->as_register(); + Register res = dest->as_register(); + Register rreg = right->as_register(); + switch (code) { + case lir_add: __ add (res, lreg, rreg); break; + case lir_sub: __ sub (res, lreg, rreg); break; + case lir_mul: __ mullw(res, lreg, rreg); break; + default: ShouldNotReachHere(); + } + } + } else { + assert (right->is_constant(), "must be constant"); + + if (dest->is_single_cpu()) { + Register lreg = left->as_register(); + Register res = dest->as_register(); + int simm16 = right->as_constant_ptr()->as_jint(); + + switch (code) { + case lir_sub: assert(Assembler::is_simm16(-simm16), "cannot encode"); // see do_ArithmeticOp_Int + simm16 = -simm16; + case lir_add: if (res == lreg && simm16 == 0) break; + __ addi(res, lreg, simm16); break; + case lir_mul: if (res == lreg && simm16 == 1) break; + __ mulli(res, lreg, simm16); break; + default: ShouldNotReachHere(); + } + } else { + Register lreg = left->as_pointer_register(); + Register res = dest->as_register_lo(); + long con = right->as_constant_ptr()->as_jlong(); + assert(Assembler::is_simm16(con), "must be simm16"); + + switch (code) { + case lir_sub: assert(Assembler::is_simm16(-con), "cannot encode"); // see do_ArithmeticOp_Long + con = -con; + case lir_add: if (res == lreg && con == 0) break; + __ addi(res, lreg, (int)con); break; + case lir_mul: if (res == lreg && con == 1) break; + __ mulli(res, lreg, (int)con); break; + default: ShouldNotReachHere(); + } + } + } +} + + +void LIR_Assembler::fpop() { + Unimplemented(); + // do nothing +} + + +void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr thread, LIR_Opr dest, LIR_Op* op) { + switch (code) { + case lir_sqrt: { + __ fsqrt(dest->as_double_reg(), value->as_double_reg()); + break; + } + case lir_abs: { + __ fabs(dest->as_double_reg(), value->as_double_reg()); + break; + } + default: { + ShouldNotReachHere(); + break; + } + } +} + + +void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) { + if (right->is_constant()) { // see do_LogicOp + long uimm; + Register d, l; + if (dest->is_single_cpu()) { + uimm = right->as_constant_ptr()->as_jint(); + d = dest->as_register(); + l = left->as_register(); + } else { + uimm = right->as_constant_ptr()->as_jlong(); + d = dest->as_register_lo(); + l = left->as_register_lo(); + } + long uimms = (unsigned long)uimm >> 16, + uimmss = (unsigned long)uimm >> 32; + + switch (code) { + case lir_logic_and: + if (uimmss != 0 || (uimms != 0 && (uimm & 0xFFFF) != 0) || is_power_of_2_long(uimm)) { + __ andi(d, l, uimm); // special cases + } else if (uimms != 0) { __ andis_(d, l, uimms); } + else { __ andi_(d, l, uimm); } + break; + + case lir_logic_or: + if (uimms != 0) { assert((uimm & 0xFFFF) == 0, "sanity"); __ oris(d, l, uimms); } + else { __ ori(d, l, uimm); } + break; + + case lir_logic_xor: + if (uimm == -1) { __ nand(d, l, l); } // special case + else if (uimms != 0) { assert((uimm & 0xFFFF) == 0, "sanity"); __ xoris(d, l, uimms); } + else { __ xori(d, l, uimm); } + break; + + default: ShouldNotReachHere(); + } + } else { + assert(right->is_register(), "right should be in register"); + + if (dest->is_single_cpu()) { + switch (code) { + case lir_logic_and: __ andr(dest->as_register(), left->as_register(), right->as_register()); break; + case lir_logic_or: __ orr (dest->as_register(), left->as_register(), right->as_register()); break; + case lir_logic_xor: __ xorr(dest->as_register(), left->as_register(), right->as_register()); break; + default: ShouldNotReachHere(); + } + } else { + Register l = (left->is_single_cpu() && left->is_oop_register()) ? left->as_register() : + left->as_register_lo(); + Register r = (right->is_single_cpu() && right->is_oop_register()) ? right->as_register() : + right->as_register_lo(); + + switch (code) { + case lir_logic_and: __ andr(dest->as_register_lo(), l, r); break; + case lir_logic_or: __ orr (dest->as_register_lo(), l, r); break; + case lir_logic_xor: __ xorr(dest->as_register_lo(), l, r); break; + default: ShouldNotReachHere(); + } + } + } +} + + +int LIR_Assembler::shift_amount(BasicType t) { + int elem_size = type2aelembytes(t); + switch (elem_size) { + case 1 : return 0; + case 2 : return 1; + case 4 : return 2; + case 8 : return 3; + } + ShouldNotReachHere(); + return -1; +} + + +void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) { + info->add_register_oop(exceptionOop); + + // Reuse the debug info from the safepoint poll for the throw op itself. + address pc_for_athrow = __ pc(); + int pc_for_athrow_offset = __ offset(); + //RelocationHolder rspec = internal_word_Relocation::spec(pc_for_athrow); + //__ relocate(rspec); + //__ load_const(exceptionPC->as_register(), pc_for_athrow, R0); + __ calculate_address_from_global_toc(exceptionPC->as_register(), pc_for_athrow, true, true, /*add_relocation*/ true); + add_call_info(pc_for_athrow_offset, info); // for exception handler + + address stub = Runtime1::entry_for(compilation()->has_fpu_code() ? Runtime1::handle_exception_id + : Runtime1::handle_exception_nofpu_id); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + __ bctr(); +} + + +void LIR_Assembler::unwind_op(LIR_Opr exceptionOop) { + // Note: Not used with EnableDebuggingOnDemand. + assert(exceptionOop->as_register() == R3, "should match"); + __ b(_unwind_handler_entry); +} + + +void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { + Register src = op->src()->as_register(); + Register dst = op->dst()->as_register(); + Register src_pos = op->src_pos()->as_register(); + Register dst_pos = op->dst_pos()->as_register(); + Register length = op->length()->as_register(); + Register tmp = op->tmp()->as_register(); + Register tmp2 = R0; + + int flags = op->flags(); + ciArrayKlass* default_type = op->expected_type(); + BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL; + if (basic_type == T_ARRAY) basic_type = T_OBJECT; + + // Set up the arraycopy stub information. + ArrayCopyStub* stub = op->stub(); + const int frame_resize = frame::abi_reg_args_size - sizeof(frame::jit_abi); // C calls need larger frame. + + // Always do stub if no type information is available. It's ok if + // the known type isn't loaded since the code sanity checks + // in debug mode and the type isn't required when we know the exact type + // also check that the type is an array type. + if (op->expected_type() == NULL) { + assert(src->is_nonvolatile() && src_pos->is_nonvolatile() && dst->is_nonvolatile() && dst_pos->is_nonvolatile() && + length->is_nonvolatile(), "must preserve"); + // 3 parms are int. Convert to long. + __ mr(R3_ARG1, src); + __ extsw(R4_ARG2, src_pos); + __ mr(R5_ARG3, dst); + __ extsw(R6_ARG4, dst_pos); + __ extsw(R7_ARG5, length); + address copyfunc_addr = StubRoutines::generic_arraycopy(); + + if (copyfunc_addr == NULL) { // Use C version if stub was not generated. + address entry = CAST_FROM_FN_PTR(address, Runtime1::arraycopy); + __ call_c_with_frame_resize(entry, frame_resize); + } else { +#ifndef PRODUCT + if (PrintC1Statistics) { + address counter = (address)&Runtime1::_generic_arraycopystub_cnt; + int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true); + __ lwz(R11_scratch1, simm16_offs, tmp); + __ addi(R11_scratch1, R11_scratch1, 1); + __ stw(R11_scratch1, simm16_offs, tmp); + } +#endif + __ call_c_with_frame_resize(copyfunc_addr, /*stub does not need resized frame*/ 0); + + __ nand(tmp, R3_RET, R3_RET); + __ subf(length, tmp, length); + __ add(src_pos, tmp, src_pos); + __ add(dst_pos, tmp, dst_pos); + } + + __ cmpwi(CCR0, R3_RET, 0); + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::less), *stub->entry()); + __ bind(*stub->continuation()); + return; + } + + assert(default_type != NULL && default_type->is_array_klass(), "must be true at this point"); + Label cont, slow, copyfunc; + + bool simple_check_flag_set = flags & (LIR_OpArrayCopy::src_null_check | + LIR_OpArrayCopy::dst_null_check | + LIR_OpArrayCopy::src_pos_positive_check | + LIR_OpArrayCopy::dst_pos_positive_check | + LIR_OpArrayCopy::length_positive_check); + + // Use only one conditional branch for simple checks. + if (simple_check_flag_set) { + ConditionRegister combined_check = CCR1, tmp_check = CCR1; + + // Make sure src and dst are non-null. + if (flags & LIR_OpArrayCopy::src_null_check) { + __ cmpdi(combined_check, src, 0); + tmp_check = CCR0; + } + + if (flags & LIR_OpArrayCopy::dst_null_check) { + __ cmpdi(tmp_check, dst, 0); + if (tmp_check != combined_check) { + __ cror(combined_check, Assembler::equal, tmp_check, Assembler::equal); + } + tmp_check = CCR0; + } + + // Clear combined_check.eq if not already used. + if (tmp_check == combined_check) { + __ crandc(combined_check, Assembler::equal, combined_check, Assembler::equal); + tmp_check = CCR0; + } + + if (flags & LIR_OpArrayCopy::src_pos_positive_check) { + // Test src_pos register. + __ cmpwi(tmp_check, src_pos, 0); + __ cror(combined_check, Assembler::equal, tmp_check, Assembler::less); + } + + if (flags & LIR_OpArrayCopy::dst_pos_positive_check) { + // Test dst_pos register. + __ cmpwi(tmp_check, dst_pos, 0); + __ cror(combined_check, Assembler::equal, tmp_check, Assembler::less); + } + + if (flags & LIR_OpArrayCopy::length_positive_check) { + // Make sure length isn't negative. + __ cmpwi(tmp_check, length, 0); + __ cror(combined_check, Assembler::equal, tmp_check, Assembler::less); + } + + __ beq(combined_check, slow); + } + + // Higher 32bits must be null. + __ extsw(length, length); + + __ extsw(src_pos, src_pos); + if (flags & LIR_OpArrayCopy::src_range_check) { + __ lwz(tmp2, arrayOopDesc::length_offset_in_bytes(), src); + __ add(tmp, length, src_pos); + __ cmpld(CCR0, tmp2, tmp); + __ ble(CCR0, slow); + } + + __ extsw(dst_pos, dst_pos); + if (flags & LIR_OpArrayCopy::dst_range_check) { + __ lwz(tmp2, arrayOopDesc::length_offset_in_bytes(), dst); + __ add(tmp, length, dst_pos); + __ cmpld(CCR0, tmp2, tmp); + __ ble(CCR0, slow); + } + + int shift = shift_amount(basic_type); + + if (!(flags & LIR_OpArrayCopy::type_check)) { + __ b(cont); + } else { + // We don't know the array types are compatible. + if (basic_type != T_OBJECT) { + // Simple test for basic type arrays. + if (UseCompressedClassPointers) { + // We don't need decode because we just need to compare. + __ lwz(tmp, oopDesc::klass_offset_in_bytes(), src); + __ lwz(tmp2, oopDesc::klass_offset_in_bytes(), dst); + __ cmpw(CCR0, tmp, tmp2); + } else { + __ ld(tmp, oopDesc::klass_offset_in_bytes(), src); + __ ld(tmp2, oopDesc::klass_offset_in_bytes(), dst); + __ cmpd(CCR0, tmp, tmp2); + } + __ beq(CCR0, cont); + } else { + // For object arrays, if src is a sub class of dst then we can + // safely do the copy. + address copyfunc_addr = StubRoutines::checkcast_arraycopy(); + + const Register sub_klass = R5, super_klass = R4; // like CheckCast/InstanceOf + assert_different_registers(tmp, tmp2, sub_klass, super_klass); + + __ load_klass(sub_klass, src); + __ load_klass(super_klass, dst); + + __ check_klass_subtype_fast_path(sub_klass, super_klass, tmp, tmp2, + &cont, copyfunc_addr != NULL ? ©func : &slow, NULL); + + address slow_stc = Runtime1::entry_for(Runtime1::slow_subtype_check_id); + //__ load_const_optimized(tmp, slow_stc, tmp2); + __ calculate_address_from_global_toc(tmp, slow_stc, true, true, false); + __ mtctr(tmp); + __ bctrl(); // sets CR0 + __ beq(CCR0, cont); + + if (copyfunc_addr != NULL) { // Use stub if available. + __ bind(copyfunc); + // Src is not a sub class of dst so we have to do a + // per-element check. + int mask = LIR_OpArrayCopy::src_objarray|LIR_OpArrayCopy::dst_objarray; + if ((flags & mask) != mask) { + assert(flags & mask, "one of the two should be known to be an object array"); + + if (!(flags & LIR_OpArrayCopy::src_objarray)) { + __ load_klass(tmp, src); + } else if (!(flags & LIR_OpArrayCopy::dst_objarray)) { + __ load_klass(tmp, dst); + } + + __ lwz(tmp2, in_bytes(Klass::layout_helper_offset()), tmp); + + jint objArray_lh = Klass::array_layout_helper(T_OBJECT); + __ load_const_optimized(tmp, objArray_lh); + __ cmpw(CCR0, tmp, tmp2); + __ bne(CCR0, slow); + } + + Register src_ptr = R3_ARG1; + Register dst_ptr = R4_ARG2; + Register len = R5_ARG3; + Register chk_off = R6_ARG4; + Register super_k = R7_ARG5; + + __ addi(src_ptr, src, arrayOopDesc::base_offset_in_bytes(basic_type)); + __ addi(dst_ptr, dst, arrayOopDesc::base_offset_in_bytes(basic_type)); + if (shift == 0) { + __ add(src_ptr, src_pos, src_ptr); + __ add(dst_ptr, dst_pos, dst_ptr); + } else { + __ sldi(tmp, src_pos, shift); + __ sldi(tmp2, dst_pos, shift); + __ add(src_ptr, tmp, src_ptr); + __ add(dst_ptr, tmp2, dst_ptr); + } + + __ load_klass(tmp, dst); + __ mr(len, length); + + int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); + __ ld(super_k, ek_offset, tmp); + + int sco_offset = in_bytes(Klass::super_check_offset_offset()); + __ lwz(chk_off, sco_offset, super_k); + + __ call_c_with_frame_resize(copyfunc_addr, /*stub does not need resized frame*/ 0); + +#ifndef PRODUCT + if (PrintC1Statistics) { + Label failed; + __ cmpwi(CCR0, R3_RET, 0); + __ bne(CCR0, failed); + address counter = (address)&Runtime1::_arraycopy_checkcast_cnt; + int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true); + __ lwz(R11_scratch1, simm16_offs, tmp); + __ addi(R11_scratch1, R11_scratch1, 1); + __ stw(R11_scratch1, simm16_offs, tmp); + __ bind(failed); + } +#endif + + __ nand(tmp, R3_RET, R3_RET); + __ cmpwi(CCR0, R3_RET, 0); + __ beq(CCR0, *stub->continuation()); + +#ifndef PRODUCT + if (PrintC1Statistics) { + address counter = (address)&Runtime1::_arraycopy_checkcast_attempt_cnt; + int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true); + __ lwz(R11_scratch1, simm16_offs, tmp); + __ addi(R11_scratch1, R11_scratch1, 1); + __ stw(R11_scratch1, simm16_offs, tmp); + } +#endif + + __ subf(length, tmp, length); + __ add(src_pos, tmp, src_pos); + __ add(dst_pos, tmp, dst_pos); + } + } + } + __ bind(slow); + __ b(*stub->entry()); + __ bind(cont); + +#ifdef ASSERT + if (basic_type != T_OBJECT || !(flags & LIR_OpArrayCopy::type_check)) { + // Sanity check the known type with the incoming class. For the + // primitive case the types must match exactly with src.klass and + // dst.klass each exactly matching the default type. For the + // object array case, if no type check is needed then either the + // dst type is exactly the expected type and the src type is a + // subtype which we can't check or src is the same array as dst + // but not necessarily exactly of type default_type. + Label known_ok, halt; + metadata2reg(op->expected_type()->constant_encoding(), tmp); + if (UseCompressedClassPointers) { + // Tmp holds the default type. It currently comes uncompressed after the + // load of a constant, so encode it. + __ encode_klass_not_null(tmp); + // Load the raw value of the dst klass, since we will be comparing + // uncompressed values directly. + __ lwz(tmp2, oopDesc::klass_offset_in_bytes(), dst); + __ cmpw(CCR0, tmp, tmp2); + if (basic_type != T_OBJECT) { + __ bne(CCR0, halt); + // Load the raw value of the src klass. + __ lwz(tmp2, oopDesc::klass_offset_in_bytes(), src); + __ cmpw(CCR0, tmp, tmp2); + __ beq(CCR0, known_ok); + } else { + __ beq(CCR0, known_ok); + __ cmpw(CCR0, src, dst); + __ beq(CCR0, known_ok); + } + } else { + __ ld(tmp2, oopDesc::klass_offset_in_bytes(), dst); + __ cmpd(CCR0, tmp, tmp2); + if (basic_type != T_OBJECT) { + __ bne(CCR0, halt); + // Load the raw value of the src klass. + __ ld(tmp2, oopDesc::klass_offset_in_bytes(), src); + __ cmpd(CCR0, tmp, tmp2); + __ beq(CCR0, known_ok); + } else { + __ beq(CCR0, known_ok); + __ cmpd(CCR0, src, dst); + __ beq(CCR0, known_ok); + } + } + __ bind(halt); + __ stop("incorrect type information in arraycopy"); + __ bind(known_ok); + } +#endif + +#ifndef PRODUCT + if (PrintC1Statistics) { + address counter = Runtime1::arraycopy_count_address(basic_type); + int simm16_offs = __ load_const_optimized(tmp, counter, tmp2, true); + __ lwz(R11_scratch1, simm16_offs, tmp); + __ addi(R11_scratch1, R11_scratch1, 1); + __ stw(R11_scratch1, simm16_offs, tmp); + } +#endif + + Register src_ptr = R3_ARG1; + Register dst_ptr = R4_ARG2; + Register len = R5_ARG3; + + __ addi(src_ptr, src, arrayOopDesc::base_offset_in_bytes(basic_type)); + __ addi(dst_ptr, dst, arrayOopDesc::base_offset_in_bytes(basic_type)); + if (shift == 0) { + __ add(src_ptr, src_pos, src_ptr); + __ add(dst_ptr, dst_pos, dst_ptr); + } else { + __ sldi(tmp, src_pos, shift); + __ sldi(tmp2, dst_pos, shift); + __ add(src_ptr, tmp, src_ptr); + __ add(dst_ptr, tmp2, dst_ptr); + } + + bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0; + bool aligned = (flags & LIR_OpArrayCopy::unaligned) == 0; + const char *name; + address entry = StubRoutines::select_arraycopy_function(basic_type, aligned, disjoint, name, false); + + // Arraycopy stubs takes a length in number of elements, so don't scale it. + __ mr(len, length); + __ call_c_with_frame_resize(entry, /*stub does not need resized frame*/ 0); + + __ bind(*stub->continuation()); +} + + +void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, LIR_Opr count, LIR_Opr dest, LIR_Opr tmp) { + if (dest->is_single_cpu()) { + __ rldicl(tmp->as_register(), count->as_register(), 0, 64-5); +#ifdef _LP64 + if (left->type() == T_OBJECT) { + switch (code) { + case lir_shl: __ sld(dest->as_register(), left->as_register(), tmp->as_register()); break; + case lir_shr: __ srad(dest->as_register(), left->as_register(), tmp->as_register()); break; + case lir_ushr: __ srd(dest->as_register(), left->as_register(), tmp->as_register()); break; + default: ShouldNotReachHere(); + } + } else +#endif + switch (code) { + case lir_shl: __ slw(dest->as_register(), left->as_register(), tmp->as_register()); break; + case lir_shr: __ sraw(dest->as_register(), left->as_register(), tmp->as_register()); break; + case lir_ushr: __ srw(dest->as_register(), left->as_register(), tmp->as_register()); break; + default: ShouldNotReachHere(); + } + } else { + __ rldicl(tmp->as_register(), count->as_register(), 0, 64-6); + switch (code) { + case lir_shl: __ sld(dest->as_register_lo(), left->as_register_lo(), tmp->as_register()); break; + case lir_shr: __ srad(dest->as_register_lo(), left->as_register_lo(), tmp->as_register()); break; + case lir_ushr: __ srd(dest->as_register_lo(), left->as_register_lo(), tmp->as_register()); break; + default: ShouldNotReachHere(); + } + } +} + + +void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, jint count, LIR_Opr dest) { +#ifdef _LP64 + if (left->type() == T_OBJECT) { + count = count & 63; // Shouldn't shift by more than sizeof(intptr_t). + if (count == 0) { __ mr_if_needed(dest->as_register_lo(), left->as_register()); } + else { + switch (code) { + case lir_shl: __ sldi(dest->as_register_lo(), left->as_register(), count); break; + case lir_shr: __ sradi(dest->as_register_lo(), left->as_register(), count); break; + case lir_ushr: __ srdi(dest->as_register_lo(), left->as_register(), count); break; + default: ShouldNotReachHere(); + } + } + return; + } +#endif + + if (dest->is_single_cpu()) { + count = count & 0x1F; // Java spec + if (count == 0) { __ mr_if_needed(dest->as_register(), left->as_register()); } + else { + switch (code) { + case lir_shl: __ slwi(dest->as_register(), left->as_register(), count); break; + case lir_shr: __ srawi(dest->as_register(), left->as_register(), count); break; + case lir_ushr: __ srwi(dest->as_register(), left->as_register(), count); break; + default: ShouldNotReachHere(); + } + } + } else if (dest->is_double_cpu()) { + count = count & 63; // Java spec + if (count == 0) { __ mr_if_needed(dest->as_pointer_register(), left->as_pointer_register()); } + else { + switch (code) { + case lir_shl: __ sldi(dest->as_pointer_register(), left->as_pointer_register(), count); break; + case lir_shr: __ sradi(dest->as_pointer_register(), left->as_pointer_register(), count); break; + case lir_ushr: __ srdi(dest->as_pointer_register(), left->as_pointer_register(), count); break; + default: ShouldNotReachHere(); + } + } + } else { + ShouldNotReachHere(); + } +} + + +void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { + if (op->init_check()) { + if (!os::zero_page_read_protected() || !ImplicitNullChecks) { + explicit_null_check(op->klass()->as_register(), op->stub()->info()); + } else { + add_debug_info_for_null_check_here(op->stub()->info()); + } + __ lbz(op->tmp1()->as_register(), + in_bytes(InstanceKlass::init_state_offset()), op->klass()->as_register()); + __ cmpwi(CCR0, op->tmp1()->as_register(), InstanceKlass::fully_initialized); + __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CCR0, Assembler::equal), *op->stub()->entry()); + } + __ allocate_object(op->obj()->as_register(), + op->tmp1()->as_register(), + op->tmp2()->as_register(), + op->tmp3()->as_register(), + op->header_size(), + op->object_size(), + op->klass()->as_register(), + *op->stub()->entry()); + + __ bind(*op->stub()->continuation()); + __ verify_oop(op->obj()->as_register()); +} + + +void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { + LP64_ONLY( __ extsw(op->len()->as_register(), op->len()->as_register()); ) + if (UseSlowPath || + (!UseFastNewObjectArray && (op->type() == T_OBJECT || op->type() == T_ARRAY)) || + (!UseFastNewTypeArray && (op->type() != T_OBJECT && op->type() != T_ARRAY))) { + __ b(*op->stub()->entry()); + } else { + __ allocate_array(op->obj()->as_register(), + op->len()->as_register(), + op->tmp1()->as_register(), + op->tmp2()->as_register(), + op->tmp3()->as_register(), + arrayOopDesc::header_size(op->type()), + type2aelembytes(op->type()), + op->klass()->as_register(), + *op->stub()->entry()); + } + __ bind(*op->stub()->continuation()); +} + + +void LIR_Assembler::type_profile_helper(Register mdo, int mdo_offset_bias, + ciMethodData *md, ciProfileData *data, + Register recv, Register tmp1, Label* update_done) { + uint i; + for (i = 0; i < VirtualCallData::row_limit(); i++) { + Label next_test; + // See if the receiver is receiver[n]. + __ ld(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - mdo_offset_bias, mdo); + __ verify_klass_ptr(tmp1); + __ cmpd(CCR0, recv, tmp1); + __ bne(CCR0, next_test); + + __ ld(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + __ addi(tmp1, tmp1, DataLayout::counter_increment); + __ std(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + __ b(*update_done); + + __ bind(next_test); + } + + // Didn't find receiver; find next empty slot and fill it in. + for (i = 0; i < VirtualCallData::row_limit(); i++) { + Label next_test; + __ ld(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - mdo_offset_bias, mdo); + __ cmpdi(CCR0, tmp1, 0); + __ bne(CCR0, next_test); + __ li(tmp1, DataLayout::counter_increment); + __ std(recv, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)) - mdo_offset_bias, mdo); + __ std(tmp1, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + __ b(*update_done); + + __ bind(next_test); + } +} + + +void LIR_Assembler::setup_md_access(ciMethod* method, int bci, + ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias) { + md = method->method_data_or_null(); + assert(md != NULL, "Sanity"); + data = md->bci_to_data(bci); + assert(data != NULL, "need data for checkcast"); + assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); + if (!Assembler::is_simm16(md->byte_offset_of_slot(data, DataLayout::header_offset()) + data->size_in_bytes())) { + // The offset is large so bias the mdo by the base of the slot so + // that the ld can use simm16s to reference the slots of the data. + mdo_offset_bias = md->byte_offset_of_slot(data, DataLayout::header_offset()); + } +} + + +void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null) { + Register obj = op->object()->as_register(); + Register k_RInfo = op->tmp1()->as_register(); + Register klass_RInfo = op->tmp2()->as_register(); + Register Rtmp1 = op->tmp3()->as_register(); + Register dst = op->result_opr()->as_register(); + ciKlass* k = op->klass(); + bool should_profile = op->should_profile(); + bool move_obj_to_dst = (op->code() == lir_checkcast); + // Attention: do_temp(opTypeCheck->_object) is not used, i.e. obj may be same as one of the temps. + bool reg_conflict = (obj == k_RInfo || obj == klass_RInfo || obj == Rtmp1); + bool restore_obj = move_obj_to_dst && reg_conflict; + + __ cmpdi(CCR0, obj, 0); + if (move_obj_to_dst || reg_conflict) { + __ mr_if_needed(dst, obj); + if (reg_conflict) { obj = dst; } + } + + ciMethodData* md; + ciProfileData* data; + int mdo_offset_bias = 0; + if (should_profile) { + ciMethod* method = op->profiled_method(); + assert(method != NULL, "Should have method"); + setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias); + + Register mdo = k_RInfo; + Register data_val = Rtmp1; + Label not_null; + __ bne(CCR0, not_null); + metadata2reg(md->constant_encoding(), mdo); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + __ lbz(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo); + __ ori(data_val, data_val, BitData::null_seen_byte_constant()); + __ stb(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo); + __ b(*obj_is_null); + __ bind(not_null); + } else { + __ beq(CCR0, *obj_is_null); + } + + // get object class + __ load_klass(klass_RInfo, obj); + + if (k->is_loaded()) { + metadata2reg(k->constant_encoding(), k_RInfo); + } else { + klass2reg_with_patching(k_RInfo, op->info_for_patch()); + } + + Label profile_cast_failure, failure_restore_obj, profile_cast_success; + Label *failure_target = should_profile ? &profile_cast_failure : failure; + Label *success_target = should_profile ? &profile_cast_success : success; + + if (op->fast_check()) { + assert_different_registers(klass_RInfo, k_RInfo); + __ cmpd(CCR0, k_RInfo, klass_RInfo); + if (should_profile) { + __ bne(CCR0, *failure_target); + // Fall through to success case. + } else { + __ beq(CCR0, *success); + // Fall through to failure case. + } + } else { + bool need_slow_path = true; + if (k->is_loaded()) { + if ((int) k->super_check_offset() != in_bytes(Klass::secondary_super_cache_offset())) { + need_slow_path = false; + } + // Perform the fast part of the checking logic. + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, R0, (need_slow_path ? success_target : NULL), + failure_target, NULL, RegisterOrConstant(k->super_check_offset())); + } else { + // Perform the fast part of the checking logic. + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, R0, success_target, failure_target); + } + if (!need_slow_path) { + if (!should_profile) { __ b(*success); } + } else { + // Call out-of-line instance of __ check_klass_subtype_slow_path(...): + address entry = Runtime1::entry_for(Runtime1::slow_subtype_check_id); + //__ load_const_optimized(Rtmp1, entry, R0); + __ calculate_address_from_global_toc(Rtmp1, entry, true, true, false); + __ mtctr(Rtmp1); + __ bctrl(); // sets CR0 + if (should_profile) { + __ bne(CCR0, *failure_target); + // Fall through to success case. + } else { + __ beq(CCR0, *success); + // Fall through to failure case. + } + } + } + + if (should_profile) { + Register mdo = k_RInfo, recv = klass_RInfo; + assert_different_registers(mdo, recv, Rtmp1); + __ bind(profile_cast_success); + metadata2reg(md->constant_encoding(), mdo); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, Rtmp1, success); + __ b(*success); + + // Cast failure case. + __ bind(profile_cast_failure); + metadata2reg(md->constant_encoding(), mdo); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + __ ld(Rtmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + __ addi(Rtmp1, Rtmp1, -DataLayout::counter_increment); + __ std(Rtmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + } + + __ bind(*failure); + + if (restore_obj) { + __ mr(op->object()->as_register(), dst); + // Fall through to failure case. + } +} + + +void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { + LIR_Code code = op->code(); + if (code == lir_store_check) { + Register value = op->object()->as_register(); + Register array = op->array()->as_register(); + Register k_RInfo = op->tmp1()->as_register(); + Register klass_RInfo = op->tmp2()->as_register(); + Register Rtmp1 = op->tmp3()->as_register(); + bool should_profile = op->should_profile(); + + __ verify_oop(value); + CodeStub* stub = op->stub(); + // Check if it needs to be profiled. + ciMethodData* md; + ciProfileData* data; + int mdo_offset_bias = 0; + if (should_profile) { + ciMethod* method = op->profiled_method(); + assert(method != NULL, "Should have method"); + setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias); + } + Label profile_cast_success, failure, done; + Label *success_target = should_profile ? &profile_cast_success : &done; + + __ cmpdi(CCR0, value, 0); + if (should_profile) { + Label not_null; + __ bne(CCR0, not_null); + Register mdo = k_RInfo; + Register data_val = Rtmp1; + metadata2reg(md->constant_encoding(), mdo); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + __ lbz(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo); + __ ori(data_val, data_val, BitData::null_seen_byte_constant()); + __ stb(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo); + __ b(done); + __ bind(not_null); + } else { + __ beq(CCR0, done); + } + if (!os::zero_page_read_protected() || !ImplicitNullChecks) { + explicit_null_check(array, op->info_for_exception()); + } else { + add_debug_info_for_null_check_here(op->info_for_exception()); + } + __ load_klass(k_RInfo, array); + __ load_klass(klass_RInfo, value); + + // Get instance klass. + __ ld(k_RInfo, in_bytes(ObjArrayKlass::element_klass_offset()), k_RInfo); + // Perform the fast part of the checking logic. + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, R0, success_target, &failure, NULL); + + // Call out-of-line instance of __ check_klass_subtype_slow_path(...): + const address slow_path = Runtime1::entry_for(Runtime1::slow_subtype_check_id); + //__ load_const_optimized(R0, slow_path); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(slow_path)); + __ mtctr(R0); + __ bctrl(); // sets CR0 + if (!should_profile) { + __ beq(CCR0, done); + __ bind(failure); + } else { + __ bne(CCR0, failure); + // Fall through to the success case. + + Register mdo = klass_RInfo, recv = k_RInfo, tmp1 = Rtmp1; + assert_different_registers(value, mdo, recv, tmp1); + __ bind(profile_cast_success); + metadata2reg(md->constant_encoding(), mdo); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + __ load_klass(recv, value); + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &done); + __ b(done); + + // Cast failure case. + __ bind(failure); + metadata2reg(md->constant_encoding(), mdo); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + Address data_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias); + __ ld(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + __ addi(tmp1, tmp1, -DataLayout::counter_increment); + __ std(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + } + __ b(*stub->entry()); + __ bind(done); + + } else if (code == lir_checkcast) { + Label success, failure; + emit_typecheck_helper(op, &success, /*fallthru*/&failure, &success); // Moves obj to dst. + __ b(*op->stub()->entry()); + __ align(32, 12); + __ bind(success); + } else if (code == lir_instanceof) { + Register dst = op->result_opr()->as_register(); + Label success, failure, done; + emit_typecheck_helper(op, &success, /*fallthru*/&failure, &failure); + __ li(dst, 0); + __ b(done); + __ align(32, 12); + __ bind(success); + __ li(dst, 1); + __ bind(done); + } else { + ShouldNotReachHere(); + } +} + + +void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { + Register addr = op->addr()->as_pointer_register(); + Register cmp_value = noreg, new_value = noreg; + bool is_64bit = false; + + if (op->code() == lir_cas_long) { + cmp_value = op->cmp_value()->as_register_lo(); + new_value = op->new_value()->as_register_lo(); + is_64bit = true; + } else if (op->code() == lir_cas_int || op->code() == lir_cas_obj) { + cmp_value = op->cmp_value()->as_register(); + new_value = op->new_value()->as_register(); + if (op->code() == lir_cas_obj) { + if (UseCompressedOops) { + Register t1 = op->tmp1()->as_register(); + Register t2 = op->tmp2()->as_register(); + cmp_value = __ encode_heap_oop(t1, cmp_value); + new_value = __ encode_heap_oop(t2, new_value); + } else { + is_64bit = true; + } + } + } else { + Unimplemented(); + } + + if (is_64bit) { + __ cmpxchgd(BOOL_RESULT, /*current_value=*/R0, cmp_value, new_value, addr, + MacroAssembler::MemBarFenceAfter, + MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, NULL, /*check without ldarx first*/true); + } else { + __ cmpxchgw(BOOL_RESULT, /*current_value=*/R0, cmp_value, new_value, addr, + MacroAssembler::MemBarFenceAfter, + MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, /*check without ldarx first*/true); + } +} + + +void LIR_Assembler::set_24bit_FPU() { + Unimplemented(); +} + +void LIR_Assembler::reset_FPU() { + Unimplemented(); +} + + +void LIR_Assembler::breakpoint() { + __ illtrap(); +} + + +void LIR_Assembler::push(LIR_Opr opr) { + Unimplemented(); +} + +void LIR_Assembler::pop(LIR_Opr opr) { + Unimplemented(); +} + + +void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst_opr) { + Address mon_addr = frame_map()->address_for_monitor_lock(monitor_no); + Register dst = dst_opr->as_register(); + Register reg = mon_addr.base(); + int offset = mon_addr.disp(); + // Compute pointer to BasicLock. + __ add_const_optimized(dst, reg, offset); +} + + +void LIR_Assembler::emit_lock(LIR_OpLock* op) { + Register obj = op->obj_opr()->as_register(); + Register hdr = op->hdr_opr()->as_register(); + Register lock = op->lock_opr()->as_register(); + + // Obj may not be an oop. + if (op->code() == lir_lock) { + MonitorEnterStub* stub = (MonitorEnterStub*)op->stub(); + if (UseFastLocking) { + assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); + // Add debug info for NullPointerException only if one is possible. + if (op->info() != NULL) { + if (!os::zero_page_read_protected() || !ImplicitNullChecks) { + explicit_null_check(obj, op->info()); + } else { + add_debug_info_for_null_check_here(op->info()); + } + } + __ lock_object(hdr, obj, lock, op->scratch_opr()->as_register(), *op->stub()->entry()); + } else { + // always do slow locking + // note: The slow locking code could be inlined here, however if we use + // slow locking, speed doesn't matter anyway and this solution is + // simpler and requires less duplicated code - additionally, the + // slow locking code is the same in either case which simplifies + // debugging. + __ b(*op->stub()->entry()); + } + } else { + assert (op->code() == lir_unlock, "Invalid code, expected lir_unlock"); + if (UseFastLocking) { + assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); + __ unlock_object(hdr, obj, lock, *op->stub()->entry()); + } else { + // always do slow unlocking + // note: The slow unlocking code could be inlined here, however if we use + // slow unlocking, speed doesn't matter anyway and this solution is + // simpler and requires less duplicated code - additionally, the + // slow unlocking code is the same in either case which simplifies + // debugging. + __ b(*op->stub()->entry()); + } + } + __ bind(*op->stub()->continuation()); +} + + +void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { + ciMethod* method = op->profiled_method(); + int bci = op->profiled_bci(); + ciMethod* callee = op->profiled_callee(); + + // Update counter for all call types. + ciMethodData* md = method->method_data_or_null(); + assert(md != NULL, "Sanity"); + ciProfileData* data = md->bci_to_data(bci); + assert(data->is_CounterData(), "need CounterData for calls"); + assert(op->mdo()->is_single_cpu(), "mdo must be allocated"); + Register mdo = op->mdo()->as_register(); +#ifdef _LP64 + assert(op->tmp1()->is_double_cpu(), "tmp1 must be allocated"); + Register tmp1 = op->tmp1()->as_register_lo(); +#else + assert(op->tmp1()->is_single_cpu(), "tmp1 must be allocated"); + Register tmp1 = op->tmp1()->as_register(); +#endif + metadata2reg(md->constant_encoding(), mdo); + int mdo_offset_bias = 0; + if (!Assembler::is_simm16(md->byte_offset_of_slot(data, CounterData::count_offset()) + + data->size_in_bytes())) { + // The offset is large so bias the mdo by the base of the slot so + // that the ld can use simm16s to reference the slots of the data. + mdo_offset_bias = md->byte_offset_of_slot(data, CounterData::count_offset()); + __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0); + } + + Bytecodes::Code bc = method->java_code_at_bci(bci); + const bool callee_is_static = callee->is_loaded() && callee->is_static(); + // Perform additional virtual call profiling for invokevirtual and + // invokeinterface bytecodes. + if ((bc == Bytecodes::_invokevirtual || bc == Bytecodes::_invokeinterface) && + !callee_is_static && // Required for optimized MH invokes. + C1ProfileVirtualCalls) { + assert(op->recv()->is_single_cpu(), "recv must be allocated"); + Register recv = op->recv()->as_register(); + assert_different_registers(mdo, tmp1, recv); + assert(data->is_VirtualCallData(), "need VirtualCallData for virtual calls"); + ciKlass* known_klass = op->known_holder(); + if (C1OptimizeVirtualCallProfiling && known_klass != NULL) { + // We know the type that will be seen at this call site; we can + // statically update the MethodData* rather than needing to do + // dynamic tests on the receiver type. + + // NOTE: we should probably put a lock around this search to + // avoid collisions by concurrent compilations. + ciVirtualCallData* vc_data = (ciVirtualCallData*) data; + uint i; + for (i = 0; i < VirtualCallData::row_limit(); i++) { + ciKlass* receiver = vc_data->receiver(i); + if (known_klass->equals(receiver)) { + __ ld(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + __ addi(tmp1, tmp1, DataLayout::counter_increment); + __ std(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + return; + } + } + + // Receiver type not found in profile data; select an empty slot. + + // Note that this is less efficient than it should be because it + // always does a write to the receiver part of the + // VirtualCallData rather than just the first time. + for (i = 0; i < VirtualCallData::row_limit(); i++) { + ciKlass* receiver = vc_data->receiver(i); + if (receiver == NULL) { + metadata2reg(known_klass->constant_encoding(), tmp1); + __ std(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i)) - mdo_offset_bias, mdo); + + __ ld(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + __ addi(tmp1, tmp1, DataLayout::counter_increment); + __ std(tmp1, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) - mdo_offset_bias, mdo); + return; + } + } + } else { + __ load_klass(recv, recv); + Label update_done; + type_profile_helper(mdo, mdo_offset_bias, md, data, recv, tmp1, &update_done); + // Receiver did not match any saved receiver and there is no empty row for it. + // Increment total counter to indicate polymorphic case. + __ ld(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + __ addi(tmp1, tmp1, DataLayout::counter_increment); + __ std(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + + __ bind(update_done); + } + } else { + // Static call + __ ld(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + __ addi(tmp1, tmp1, DataLayout::counter_increment); + __ std(tmp1, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias, mdo); + } +} + + +void LIR_Assembler::align_backward_branch_target() { + __ align(32, 12); // Insert up to 3 nops to align with 32 byte boundary. +} + + +void LIR_Assembler::emit_delay(LIR_OpDelay* op) { + Unimplemented(); +} + + +void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest) { + assert(left->is_register(), "can only handle registers"); + + if (left->is_single_cpu()) { + __ neg(dest->as_register(), left->as_register()); + } else if (left->is_single_fpu()) { + __ fneg(dest->as_float_reg(), left->as_float_reg()); + } else if (left->is_double_fpu()) { + __ fneg(dest->as_double_reg(), left->as_double_reg()); + } else { + assert (left->is_double_cpu(), "Must be a long"); + __ neg(dest->as_register_lo(), left->as_register_lo()); + } +} + + +void LIR_Assembler::fxch(int i) { + Unimplemented(); +} + +void LIR_Assembler::fld(int i) { + Unimplemented(); +} + +void LIR_Assembler::ffree(int i) { + Unimplemented(); +} + + +void LIR_Assembler::rt_call(LIR_Opr result, address dest, + const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) { + // Stubs: Called via rt_call, but dest is a stub address (no function descriptor). + if (dest == Runtime1::entry_for(Runtime1::register_finalizer_id) || + dest == Runtime1::entry_for(Runtime1::new_multi_array_id )) { + //__ load_const_optimized(R0, dest); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(dest)); + __ mtctr(R0); + __ bctrl(); + assert(info != NULL, "sanity"); + add_call_info_here(info); + return; + } + + __ call_c_with_frame_resize(dest, /*no resizing*/ 0); + if (info != NULL) { + add_call_info_here(info); + } +} + + +void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info) { + ShouldNotReachHere(); // Not needed on _LP64. +} + +void LIR_Assembler::membar() { + __ fence(); +} + +void LIR_Assembler::membar_acquire() { + __ acquire(); +} + +void LIR_Assembler::membar_release() { + __ release(); +} + +void LIR_Assembler::membar_loadload() { + __ membar(Assembler::LoadLoad); +} + +void LIR_Assembler::membar_storestore() { + __ membar(Assembler::StoreStore); +} + +void LIR_Assembler::membar_loadstore() { + __ membar(Assembler::LoadStore); +} + +void LIR_Assembler::membar_storeload() { + __ membar(Assembler::StoreLoad); +} + + +void LIR_Assembler::leal(LIR_Opr addr_opr, LIR_Opr dest) { + LIR_Address* addr = addr_opr->as_address_ptr(); + assert(addr->scale() == LIR_Address::times_1, "no scaling on this platform"); + if (addr->index()->is_illegal()) { + __ add_const_optimized(dest->as_pointer_register(), addr->base()->as_pointer_register(), addr->disp()); + } else { + assert(addr->disp() == 0, "can't have both: index and disp"); + __ add(dest->as_pointer_register(), addr->index()->as_pointer_register(), addr->base()->as_pointer_register()); + } +} + + +void LIR_Assembler::get_thread(LIR_Opr result_reg) { + ShouldNotReachHere(); +} + + +#ifdef ASSERT +// Emit run-time assertion. +void LIR_Assembler::emit_assert(LIR_OpAssert* op) { + Unimplemented(); +} +#endif + + +void LIR_Assembler::peephole(LIR_List* lir) { + // Optimize instruction pairs before emitting. + LIR_OpList* inst = lir->instructions_list(); + for (int i = 1; i < inst->length(); i++) { + LIR_Op* op = inst->at(i); + + // 2 register-register-moves + if (op->code() == lir_move) { + LIR_Opr in2 = ((LIR_Op1*)op)->in_opr(), + res2 = ((LIR_Op1*)op)->result_opr(); + if (in2->is_register() && res2->is_register()) { + LIR_Op* prev = inst->at(i - 1); + if (prev && prev->code() == lir_move) { + LIR_Opr in1 = ((LIR_Op1*)prev)->in_opr(), + res1 = ((LIR_Op1*)prev)->result_opr(); + if (in1->is_same_register(res2) && in2->is_same_register(res1)) { + inst->remove_at(i); + } + } + } + } + + } + return; +} + + +void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr dest, LIR_Opr tmp) { + const Register Rptr = src->as_pointer_register(), + Rtmp = tmp->as_register(); + Register Rco = noreg; + if (UseCompressedOops && data->is_oop()) { + Rco = __ encode_heap_oop(Rtmp, data->as_register()); + } + + Label Lretry; + __ bind(Lretry); + + if (data->type() == T_INT) { + const Register Rold = dest->as_register(), + Rsrc = data->as_register(); + assert_different_registers(Rptr, Rtmp, Rold, Rsrc); + __ lwarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update()); + if (code == lir_xadd) { + __ add(Rtmp, Rsrc, Rold); + __ stwcx_(Rtmp, Rptr); + } else { + __ stwcx_(Rsrc, Rptr); + } + } else if (data->is_oop()) { + assert(code == lir_xchg, "xadd for oops"); + const Register Rold = dest->as_register(); + if (UseCompressedOops) { + assert_different_registers(Rptr, Rold, Rco); + __ lwarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update()); + __ stwcx_(Rco, Rptr); + } else { + const Register Robj = data->as_register(); + assert_different_registers(Rptr, Rold, Robj); + __ ldarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update()); + __ stdcx_(Robj, Rptr); + } + } else if (data->type() == T_LONG) { + const Register Rold = dest->as_register_lo(), + Rsrc = data->as_register_lo(); + assert_different_registers(Rptr, Rtmp, Rold, Rsrc); + __ ldarx(Rold, Rptr, MacroAssembler::cmpxchgx_hint_atomic_update()); + if (code == lir_xadd) { + __ add(Rtmp, Rsrc, Rold); + __ stdcx_(Rtmp, Rptr); + } else { + __ stdcx_(Rsrc, Rptr); + } + } else { + ShouldNotReachHere(); + } + + if (UseStaticBranchPredictionInCompareAndSwapPPC64) { + __ bne_predict_not_taken(CCR0, Lretry); + } else { + __ bne( CCR0, Lretry); + } + + if (UseCompressedOops && data->is_oop()) { + __ decode_heap_oop(dest->as_register()); + } +} + + +void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { + Register obj = op->obj()->as_register(); + Register tmp = op->tmp()->as_pointer_register(); + LIR_Address* mdo_addr = op->mdp()->as_address_ptr(); + ciKlass* exact_klass = op->exact_klass(); + intptr_t current_klass = op->current_klass(); + bool not_null = op->not_null(); + bool no_conflict = op->no_conflict(); + + Label Lupdate, Ldo_update, Ldone; + + bool do_null = !not_null; + bool exact_klass_set = exact_klass != NULL && ciTypeEntries::valid_ciklass(current_klass) == exact_klass; + bool do_update = !TypeEntries::is_type_unknown(current_klass) && !exact_klass_set; + + assert(do_null || do_update, "why are we here?"); + assert(!TypeEntries::was_null_seen(current_klass) || do_update, "why are we here?"); + + __ verify_oop(obj); + + if (do_null) { + if (!TypeEntries::was_null_seen(current_klass)) { + __ cmpdi(CCR0, obj, 0); + __ bne(CCR0, Lupdate); + __ ld(R0, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); + __ ori(R0, R0, TypeEntries::null_seen); + if (do_update) { + __ b(Ldo_update); + } else { + __ std(R0, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); + } + } else { + if (do_update) { + __ cmpdi(CCR0, obj, 0); + __ beq(CCR0, Ldone); + } + } +#ifdef ASSERT + } else { + __ cmpdi(CCR0, obj, 0); + __ bne(CCR0, Lupdate); + __ stop("unexpect null obj", 0x9652); +#endif + } + + __ bind(Lupdate); + if (do_update) { + Label Lnext; + const Register klass = R29_TOC; // kill and reload + bool klass_reg_used = false; +#ifdef ASSERT + if (exact_klass != NULL) { + Label ok; + klass_reg_used = true; + __ load_klass(klass, obj); + metadata2reg(exact_klass->constant_encoding(), R0); + __ cmpd(CCR0, klass, R0); + __ beq(CCR0, ok); + __ stop("exact klass and actual klass differ", 0x8564); + __ bind(ok); + } +#endif + + if (!no_conflict) { + if (exact_klass == NULL || TypeEntries::is_type_none(current_klass)) { + klass_reg_used = true; + if (exact_klass != NULL) { + __ ld(tmp, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); + metadata2reg(exact_klass->constant_encoding(), klass); + } else { + __ load_klass(klass, obj); + __ ld(tmp, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); // may kill obj + } + + // Like InterpreterMacroAssembler::profile_obj_type + __ clrrdi(R0, tmp, exact_log2(-TypeEntries::type_klass_mask)); + // Basically same as andi(R0, tmp, TypeEntries::type_klass_mask); + __ cmpd(CCR1, R0, klass); + // Klass seen before, nothing to do (regardless of unknown bit). + //beq(CCR1, do_nothing); + + __ andi_(R0, klass, TypeEntries::type_unknown); + // Already unknown. Nothing to do anymore. + //bne(CCR0, do_nothing); + __ crorc(CCR0, Assembler::equal, CCR1, Assembler::equal); // cr0 eq = cr1 eq or cr0 ne + __ beq(CCR0, Lnext); + + if (TypeEntries::is_type_none(current_klass)) { + __ clrrdi_(R0, tmp, exact_log2(-TypeEntries::type_mask)); + __ orr(R0, klass, tmp); // Combine klass and null_seen bit (only used if (tmp & type_mask)==0). + __ beq(CCR0, Ldo_update); // First time here. Set profile type. + } + + } else { + assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && + ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only"); + + __ ld(tmp, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); + __ andi_(R0, tmp, TypeEntries::type_unknown); + // Already unknown. Nothing to do anymore. + __ bne(CCR0, Lnext); + } + + // Different than before. Cannot keep accurate profile. + __ ori(R0, tmp, TypeEntries::type_unknown); + } else { + // There's a single possible klass at this profile point + assert(exact_klass != NULL, "should be"); + __ ld(tmp, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); + + if (TypeEntries::is_type_none(current_klass)) { + klass_reg_used = true; + metadata2reg(exact_klass->constant_encoding(), klass); + + __ clrrdi(R0, tmp, exact_log2(-TypeEntries::type_klass_mask)); + // Basically same as andi(R0, tmp, TypeEntries::type_klass_mask); + __ cmpd(CCR1, R0, klass); + // Klass seen before, nothing to do (regardless of unknown bit). + __ beq(CCR1, Lnext); +#ifdef ASSERT + { + Label ok; + __ clrrdi_(R0, tmp, exact_log2(-TypeEntries::type_mask)); + __ beq(CCR0, ok); // First time here. + + __ stop("unexpected profiling mismatch", 0x7865); + __ bind(ok); + } +#endif + // First time here. Set profile type. + __ orr(R0, klass, tmp); // Combine klass and null_seen bit (only used if (tmp & type_mask)==0). + } else { + assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && + ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); + + // Already unknown. Nothing to do anymore. + __ andi_(R0, tmp, TypeEntries::type_unknown); + __ bne(CCR0, Lnext); + + // Different than before. Cannot keep accurate profile. + __ ori(R0, tmp, TypeEntries::type_unknown); + } + } + + __ bind(Ldo_update); + __ std(R0, index_or_disp(mdo_addr), mdo_addr->base()->as_pointer_register()); + + __ bind(Lnext); + if (klass_reg_used) { __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R0); } // reinit + } + __ bind(Ldone); +} + + +void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) { + assert(op->crc()->is_single_cpu(), "crc must be register"); + assert(op->val()->is_single_cpu(), "byte value must be register"); + assert(op->result_opr()->is_single_cpu(), "result must be register"); + Register crc = op->crc()->as_register(); + Register val = op->val()->as_register(); + Register res = op->result_opr()->as_register(); + + assert_different_registers(val, crc, res); + + __ load_const_optimized(res, StubRoutines::crc_table_addr(), R0); + __ nand(crc, crc, crc); // ~crc + __ update_byte_crc32(crc, val, res); + __ nand(res, crc, crc); // ~crc +} + +#undef __ diff --git a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp new file mode 100644 index 00000000000..03d1faedbf9 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.hpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 CPU_PPC_VM_C1_LIRASSEMBLER_PPC_HPP +#define CPU_PPC_VM_C1_LIRASSEMBLER_PPC_HPP + + private: + + ////////////////////////////////////////////////////////////////////////////// + // PPC64 load/store emission + // + // The PPC ld/st instructions cannot accomodate displacements > 16 bits long. + // The following "pseudo" instructions (load/store) make it easier to + // use the indexed addressing mode by allowing 32 bit displacements: + // + + void explicit_null_check(Register addr, CodeEmitInfo* info); + + int store(LIR_Opr from_reg, Register base, int offset, BasicType type, bool wide, bool unaligned); + int store(LIR_Opr from_reg, Register base, Register disp, BasicType type, bool wide); + + int load(Register base, int offset, LIR_Opr to_reg, BasicType type, bool wide, bool unaligned); + int load(Register base, Register disp, LIR_Opr to_reg, BasicType type, bool wide); + + int shift_amount(BasicType t); + + // Record the type of the receiver in ReceiverTypeData. + void type_profile_helper(Register mdo, int mdo_offset_bias, + ciMethodData *md, ciProfileData *data, + Register recv, Register tmp1, Label* update_done); + // Setup pointers to MDO, MDO slot, also compute offset bias to access the slot. + void setup_md_access(ciMethod* method, int bci, + ciMethodData*& md, ciProfileData*& data, int& mdo_offset_bias); + public: + static const ConditionRegister BOOL_RESULT; + + // Emit trampoline stub for call. Call bailout() if failed. Return true on success. + bool emit_trampoline_stub_for_call(address target, Register Rtoc = noreg); + +enum { + max_static_call_stub_size = 4 * BytesPerInstWord + MacroAssembler::b64_patchable_size, + call_stub_size = max_static_call_stub_size + MacroAssembler::trampoline_stub_size, // or smaller + exception_handler_size = MacroAssembler::b64_patchable_size, // or smaller + deopt_handler_size = MacroAssembler::bl64_patchable_size +}; + +#endif // CPU_PPC_VM_C1_LIRASSEMBLER_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp new file mode 100644 index 00000000000..909d0136011 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_LIRGenerator_ppc.cpp @@ -0,0 +1,1429 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 "c1/c1_Compilation.hpp" +#include "c1/c1_FrameMap.hpp" +#include "c1/c1_Instruction.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_LIRGenerator.hpp" +#include "c1/c1_Runtime1.hpp" +#include "c1/c1_ValueStack.hpp" +#include "ci/ciArray.hpp" +#include "ci/ciObjArrayKlass.hpp" +#include "ci/ciTypeArrayKlass.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "vmreg_ppc.inline.hpp" + +#ifdef ASSERT +#define __ gen()->lir(__FILE__, __LINE__)-> +#else +#define __ gen()->lir()-> +#endif + +void LIRItem::load_byte_item() { + // Byte loads use same registers as other loads. + load_item(); +} + + +void LIRItem::load_nonconstant() { + LIR_Opr r = value()->operand(); + if (_gen->can_inline_as_constant(value())) { + if (!r->is_constant()) { + r = LIR_OprFact::value_type(value()->type()); + } + _result = r; + } else { + load_item(); + } +} + + +inline void load_int_as_long(LIR_List *ll, LIRItem &li, LIR_Opr dst) { + LIR_Opr r = li.value()->operand(); + if (r->is_register()) { + LIR_Opr dst_l = FrameMap::as_long_opr(dst->as_register()); + ll->convert(Bytecodes::_i2l, li.result(), dst_l); // Convert. + } else { + // Constants or memory get loaded with sign extend on this platform. + ll->move(li.result(), dst); + } +} + + +//-------------------------------------------------------------- +// LIRGenerator +//-------------------------------------------------------------- + +LIR_Opr LIRGenerator::exceptionOopOpr() { return FrameMap::R3_oop_opr; } +LIR_Opr LIRGenerator::exceptionPcOpr() { return FrameMap::R4_opr; } +LIR_Opr LIRGenerator::syncLockOpr() { return FrameMap::R5_opr; } // Need temp effect for MonitorEnterStub. +LIR_Opr LIRGenerator::syncTempOpr() { return FrameMap::R4_oop_opr; } // Need temp effect for MonitorEnterStub. +LIR_Opr LIRGenerator::getThreadTemp() { return LIR_OprFact::illegalOpr; } // not needed + +LIR_Opr LIRGenerator::result_register_for(ValueType* type, bool callee) { + LIR_Opr opr; + switch (type->tag()) { + case intTag: opr = FrameMap::R3_opr; break; + case objectTag: opr = FrameMap::R3_oop_opr; break; + case longTag: opr = FrameMap::R3_long_opr; break; + case floatTag: opr = FrameMap::F1_opr; break; + case doubleTag: opr = FrameMap::F1_double_opr; break; + + case addressTag: + default: ShouldNotReachHere(); return LIR_OprFact::illegalOpr; + } + + assert(opr->type_field() == as_OprType(as_BasicType(type)), "type mismatch"); + return opr; +} + +LIR_Opr LIRGenerator::rlock_callee_saved(BasicType type) { + ShouldNotReachHere(); + return LIR_OprFact::illegalOpr; +} + + +LIR_Opr LIRGenerator::rlock_byte(BasicType type) { + return new_register(T_INT); +} + + +//--------- loading items into registers -------------------------------- + +// PPC cannot inline all constants. +bool LIRGenerator::can_store_as_constant(Value v, BasicType type) const { + if (v->type()->as_IntConstant() != NULL) { + return Assembler::is_simm16(v->type()->as_IntConstant()->value()); + } else if (v->type()->as_LongConstant() != NULL) { + return Assembler::is_simm16(v->type()->as_LongConstant()->value()); + } else if (v->type()->as_ObjectConstant() != NULL) { + return v->type()->as_ObjectConstant()->value()->is_null_object(); + } else { + return false; + } +} + + +// Only simm16 constants can be inlined. +bool LIRGenerator::can_inline_as_constant(Value i) const { + return can_store_as_constant(i, as_BasicType(i->type())); +} + + +bool LIRGenerator::can_inline_as_constant(LIR_Const* c) const { + if (c->type() == T_INT) { + return Assembler::is_simm16(c->as_jint()); + } + if (c->type() == T_LONG) { + return Assembler::is_simm16(c->as_jlong()); + } + if (c->type() == T_OBJECT) { + return c->as_jobject() == NULL; + } + return false; +} + + +LIR_Opr LIRGenerator::safepoint_poll_register() { + return new_register(T_INT); +} + + +LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, + int shift, int disp, BasicType type) { + assert(base->is_register(), "must be"); + + // Accumulate fixed displacements. + if (index->is_constant()) { + disp += index->as_constant_ptr()->as_jint() << shift; + index = LIR_OprFact::illegalOpr; + } + + if (index->is_register()) { + // Apply the shift and accumulate the displacement. + if (shift > 0) { + LIR_Opr tmp = new_pointer_register(); + __ shift_left(index, shift, tmp); + index = tmp; + } + if (disp != 0) { + LIR_Opr tmp = new_pointer_register(); + if (Assembler::is_simm16(disp)) { + __ add(index, LIR_OprFact::intptrConst(disp), tmp); + index = tmp; + } else { + __ move(LIR_OprFact::intptrConst(disp), tmp); + __ add(tmp, index, tmp); + index = tmp; + } + disp = 0; + } + } else if (!Assembler::is_simm16(disp)) { + // Index is illegal so replace it with the displacement loaded into a register. + index = new_pointer_register(); + __ move(LIR_OprFact::intptrConst(disp), index); + disp = 0; + } + + // At this point we either have base + index or base + displacement. + if (disp == 0) { + return new LIR_Address(base, index, type); + } else { + assert(Assembler::is_simm16(disp), "must be"); + return new LIR_Address(base, disp, type); + } +} + + +LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, + BasicType type, bool needs_card_mark) { + int elem_size = type2aelembytes(type); + int shift = exact_log2(elem_size); + + LIR_Opr base_opr; + int offset = arrayOopDesc::base_offset_in_bytes(type); + + if (index_opr->is_constant()) { + int i = index_opr->as_constant_ptr()->as_jint(); + int array_offset = i * elem_size; + if (Assembler::is_simm16(array_offset + offset)) { + base_opr = array_opr; + offset = array_offset + offset; + } else { + base_opr = new_pointer_register(); + if (Assembler::is_simm16(array_offset)) { + __ add(array_opr, LIR_OprFact::intptrConst(array_offset), base_opr); + } else { + __ move(LIR_OprFact::intptrConst(array_offset), base_opr); + __ add(base_opr, array_opr, base_opr); + } + } + } else { +#ifdef _LP64 + if (index_opr->type() == T_INT) { + LIR_Opr tmp = new_register(T_LONG); + __ convert(Bytecodes::_i2l, index_opr, tmp); + index_opr = tmp; + } +#endif + + base_opr = new_pointer_register(); + assert (index_opr->is_register(), "Must be register"); + if (shift > 0) { + __ shift_left(index_opr, shift, base_opr); + __ add(base_opr, array_opr, base_opr); + } else { + __ add(index_opr, array_opr, base_opr); + } + } + if (needs_card_mark) { + LIR_Opr ptr = new_pointer_register(); + __ add(base_opr, LIR_OprFact::intptrConst(offset), ptr); + return new LIR_Address(ptr, type); + } else { + return new LIR_Address(base_opr, offset, type); + } +} + + +LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) { + LIR_Opr r = NULL; + if (type == T_LONG) { + r = LIR_OprFact::longConst(x); + } else if (type == T_INT) { + r = LIR_OprFact::intConst(x); + } else { + ShouldNotReachHere(); + } + if (!Assembler::is_simm16(x)) { + LIR_Opr tmp = new_register(type); + __ move(r, tmp); + return tmp; + } + return r; +} + + +void LIRGenerator::increment_counter(address counter, BasicType type, int step) { + LIR_Opr pointer = new_pointer_register(); + __ move(LIR_OprFact::intptrConst(counter), pointer); + LIR_Address* addr = new LIR_Address(pointer, type); + increment_counter(addr, step); +} + + +void LIRGenerator::increment_counter(LIR_Address* addr, int step) { + LIR_Opr temp = new_register(addr->type()); + __ move(addr, temp); + __ add(temp, load_immediate(step, addr->type()), temp); + __ move(temp, addr); +} + + +void LIRGenerator::cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info) { + LIR_Opr tmp = FrameMap::R0_opr; + __ load(new LIR_Address(base, disp, T_INT), tmp, info); + __ cmp(condition, tmp, c); +} + + +void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr base, + int disp, BasicType type, CodeEmitInfo* info) { + LIR_Opr tmp = FrameMap::R0_opr; + __ load(new LIR_Address(base, disp, type), tmp, info); + __ cmp(condition, reg, tmp); +} + + +void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr base, + LIR_Opr disp, BasicType type, CodeEmitInfo* info) { + LIR_Opr tmp = FrameMap::R0_opr; + __ load(new LIR_Address(base, disp, type), tmp, info); + __ cmp(condition, reg, tmp); +} + + +bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, int c, LIR_Opr result, LIR_Opr tmp) { + assert(left != result, "should be different registers"); + if (is_power_of_2(c + 1)) { + __ shift_left(left, log2_intptr(c + 1), result); + __ sub(result, left, result); + return true; + } else if (is_power_of_2(c - 1)) { + __ shift_left(left, log2_intptr(c - 1), result); + __ add(result, left, result); + return true; + } + return false; +} + + +void LIRGenerator::store_stack_parameter(LIR_Opr item, ByteSize offset_from_sp) { + BasicType t = item->type(); + LIR_Opr sp_opr = FrameMap::SP_opr; + if ((t == T_LONG || t == T_DOUBLE) && + ((in_bytes(offset_from_sp) - STACK_BIAS) % 8 != 0)) { + __ unaligned_move(item, new LIR_Address(sp_opr, in_bytes(offset_from_sp), t)); + } else { + __ move(item, new LIR_Address(sp_opr, in_bytes(offset_from_sp), t)); + } +} + + +//---------------------------------------------------------------------- +// visitor functions +//---------------------------------------------------------------------- + +void LIRGenerator::do_StoreIndexed(StoreIndexed* x) { + assert(x->is_pinned(),""); + bool needs_range_check = x->compute_needs_range_check(); + bool use_length = x->length() != NULL; + bool obj_store = x->elt_type() == T_ARRAY || x->elt_type() == T_OBJECT; + bool needs_store_check = obj_store && (x->value()->as_Constant() == NULL || + !get_jobject_constant(x->value())->is_null_object() || + x->should_profile()); + + LIRItem array(x->array(), this); + LIRItem index(x->index(), this); + LIRItem value(x->value(), this); + LIRItem length(this); + + array.load_item(); + index.load_nonconstant(); + + if (use_length && needs_range_check) { + length.set_instruction(x->length()); + length.load_item(); + } + if (needs_store_check) { + value.load_item(); + } else { + value.load_for_store(x->elt_type()); + } + + set_no_result(x); + + // The CodeEmitInfo must be duplicated for each different + // LIR-instruction because spilling can occur anywhere between two + // instructions and so the debug information must be different. + CodeEmitInfo* range_check_info = state_for(x); + CodeEmitInfo* null_check_info = NULL; + if (x->needs_null_check()) { + null_check_info = new CodeEmitInfo(range_check_info); + } + + // Emit array address setup early so it schedules better. + LIR_Address* array_addr = emit_array_address(array.result(), index.result(), x->elt_type(), obj_store); + + if (GenerateRangeChecks && needs_range_check) { + if (use_length) { + __ cmp(lir_cond_belowEqual, length.result(), index.result()); + __ branch(lir_cond_belowEqual, T_INT, new RangeCheckStub(range_check_info, index.result())); + } else { + array_range_check(array.result(), index.result(), null_check_info, range_check_info); + // Range_check also does the null check. + null_check_info = NULL; + } + } + + if (GenerateArrayStoreCheck && needs_store_check) { + // Following registers are used by slow_subtype_check: + LIR_Opr tmp1 = FrameMap::R4_opr; // super_klass + LIR_Opr tmp2 = FrameMap::R5_opr; // sub_klass + LIR_Opr tmp3 = FrameMap::R6_opr; // temp + + CodeEmitInfo* store_check_info = new CodeEmitInfo(range_check_info); + __ store_check(value.result(), array.result(), tmp1, tmp2, tmp3, + store_check_info, x->profiled_method(), x->profiled_bci()); + } + + if (obj_store) { + // Needs GC write barriers. + pre_barrier(LIR_OprFact::address(array_addr), LIR_OprFact::illegalOpr /* pre_val */, + true /* do_load */, false /* patch */, NULL); + } + __ move(value.result(), array_addr, null_check_info); + if (obj_store) { + // Precise card mark. + post_barrier(LIR_OprFact::address(array_addr), value.result()); + } +} + + +void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { + assert(x->is_pinned(),""); + LIRItem obj(x->obj(), this); + obj.load_item(); + + set_no_result(x); + + // We use R4+R5 in order to get a temp effect. These regs are used in slow path (MonitorEnterStub). + LIR_Opr lock = FrameMap::R5_opr; + LIR_Opr scratch = FrameMap::R4_opr; + LIR_Opr hdr = FrameMap::R6_opr; + + CodeEmitInfo* info_for_exception = NULL; + if (x->needs_null_check()) { + info_for_exception = state_for(x); + } + + // This CodeEmitInfo must not have the xhandlers because here the + // object is already locked (xhandlers expects object to be unlocked). + CodeEmitInfo* info = state_for(x, x->state(), true); + monitor_enter(obj.result(), lock, hdr, scratch, x->monitor_no(), info_for_exception, info); +} + + +void LIRGenerator::do_MonitorExit(MonitorExit* x) { + assert(x->is_pinned(),""); + LIRItem obj(x->obj(), this); + obj.dont_load_item(); + + set_no_result(x); + LIR_Opr lock = FrameMap::R5_opr; + LIR_Opr hdr = FrameMap::R4_opr; // Used for slow path (MonitorExitStub). + LIR_Opr obj_temp = FrameMap::R6_opr; + monitor_exit(obj_temp, lock, hdr, LIR_OprFact::illegalOpr, x->monitor_no()); +} + + +// _ineg, _lneg, _fneg, _dneg +void LIRGenerator::do_NegateOp(NegateOp* x) { + LIRItem value(x->x(), this); + value.load_item(); + LIR_Opr reg = rlock_result(x); + __ negate(value.result(), reg); +} + + +// for _fadd, _fmul, _fsub, _fdiv, _frem +// _dadd, _dmul, _dsub, _ddiv, _drem +void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) { + switch (x->op()) { + case Bytecodes::_fadd: + case Bytecodes::_fmul: + case Bytecodes::_fsub: + case Bytecodes::_fdiv: + case Bytecodes::_dadd: + case Bytecodes::_dmul: + case Bytecodes::_dsub: + case Bytecodes::_ddiv: { + LIRItem left(x->x(), this); + LIRItem right(x->y(), this); + left.load_item(); + right.load_item(); + rlock_result(x); + arithmetic_op_fpu(x->op(), x->operand(), left.result(), right.result(), x->is_strictfp()); + } + break; + + case Bytecodes::_frem: + case Bytecodes::_drem: { + address entry = NULL; + switch (x->op()) { + case Bytecodes::_frem: + entry = CAST_FROM_FN_PTR(address, SharedRuntime::frem); + break; + case Bytecodes::_drem: + entry = CAST_FROM_FN_PTR(address, SharedRuntime::drem); + break; + default: + ShouldNotReachHere(); + } + LIR_Opr result = call_runtime(x->x(), x->y(), entry, x->type(), NULL); + set_result(x, result); + } + break; + + default: ShouldNotReachHere(); + } +} + + +// for _ladd, _lmul, _lsub, _ldiv, _lrem +void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) { + bool is_div_rem = x->op() == Bytecodes::_ldiv || x->op() == Bytecodes::_lrem; + + LIRItem right(x->y(), this); + // Missing test if instr is commutative and if we should swap. + if (right.value()->type()->as_LongConstant() && + (x->op() == Bytecodes::_lsub && right.value()->type()->as_LongConstant()->value() == ((-1)<<15)) ) { + // Sub is implemented by addi and can't support min_simm16 as constant.. + right.load_item(); + } else { + right.load_nonconstant(); + } + assert(right.is_constant() || right.is_register(), "wrong state of right"); + + if (is_div_rem) { + LIR_Opr divisor = right.result(); + if (divisor->is_register()) { + CodeEmitInfo* null_check_info = state_for(x); + __ cmp(lir_cond_equal, divisor, LIR_OprFact::longConst(0)); + __ branch(lir_cond_equal, T_LONG, new DivByZeroStub(null_check_info)); + } else { + jlong const_divisor = divisor->as_constant_ptr()->as_jlong(); + if (const_divisor == 0) { + CodeEmitInfo* null_check_info = state_for(x); + __ jump(new DivByZeroStub(null_check_info)); + rlock_result(x); + __ move(LIR_OprFact::longConst(0), x->operand()); // dummy + return; + } + if (x->op() == Bytecodes::_lrem && !is_power_of_2(const_divisor) && const_divisor != -1) { + // Remainder computation would need additional tmp != R0. + right.load_item(); + } + } + } + + LIRItem left(x->x(), this); + left.load_item(); + rlock_result(x); + if (is_div_rem) { + CodeEmitInfo* info = NULL; // Null check already done above. + LIR_Opr tmp = FrameMap::R0_opr; + if (x->op() == Bytecodes::_lrem) { + __ irem(left.result(), right.result(), x->operand(), tmp, info); + } else if (x->op() == Bytecodes::_ldiv) { + __ idiv(left.result(), right.result(), x->operand(), tmp, info); + } + } else { + arithmetic_op_long(x->op(), x->operand(), left.result(), right.result(), NULL); + } +} + + +// for: _iadd, _imul, _isub, _idiv, _irem +void LIRGenerator::do_ArithmeticOp_Int(ArithmeticOp* x) { + bool is_div_rem = x->op() == Bytecodes::_idiv || x->op() == Bytecodes::_irem; + + LIRItem right(x->y(), this); + // Missing test if instr is commutative and if we should swap. + if (right.value()->type()->as_IntConstant() && + (x->op() == Bytecodes::_isub && right.value()->type()->as_IntConstant()->value() == ((-1)<<15)) ) { + // Sub is implemented by addi and can't support min_simm16 as constant. + right.load_item(); + } else { + right.load_nonconstant(); + } + assert(right.is_constant() || right.is_register(), "wrong state of right"); + + if (is_div_rem) { + LIR_Opr divisor = right.result(); + if (divisor->is_register()) { + CodeEmitInfo* null_check_info = state_for(x); + __ cmp(lir_cond_equal, divisor, LIR_OprFact::intConst(0)); + __ branch(lir_cond_equal, T_INT, new DivByZeroStub(null_check_info)); + } else { + jint const_divisor = divisor->as_constant_ptr()->as_jint(); + if (const_divisor == 0) { + CodeEmitInfo* null_check_info = state_for(x); + __ jump(new DivByZeroStub(null_check_info)); + rlock_result(x); + __ move(LIR_OprFact::intConst(0), x->operand()); // dummy + return; + } + if (x->op() == Bytecodes::_irem && !is_power_of_2(const_divisor) && const_divisor != -1) { + // Remainder computation would need additional tmp != R0. + right.load_item(); + } + } + } + + LIRItem left(x->x(), this); + left.load_item(); + rlock_result(x); + if (is_div_rem) { + CodeEmitInfo* info = NULL; // Null check already done above. + LIR_Opr tmp = FrameMap::R0_opr; + if (x->op() == Bytecodes::_irem) { + __ irem(left.result(), right.result(), x->operand(), tmp, info); + } else if (x->op() == Bytecodes::_idiv) { + __ idiv(left.result(), right.result(), x->operand(), tmp, info); + } + } else { + arithmetic_op_int(x->op(), x->operand(), left.result(), right.result(), FrameMap::R0_opr); + } +} + + +void LIRGenerator::do_ArithmeticOp(ArithmeticOp* x) { + ValueTag tag = x->type()->tag(); + assert(x->x()->type()->tag() == tag && x->y()->type()->tag() == tag, "wrong parameters"); + switch (tag) { + case floatTag: + case doubleTag: do_ArithmeticOp_FPU(x); return; + case longTag: do_ArithmeticOp_Long(x); return; + case intTag: do_ArithmeticOp_Int(x); return; + } + ShouldNotReachHere(); +} + + +// _ishl, _lshl, _ishr, _lshr, _iushr, _lushr +void LIRGenerator::do_ShiftOp(ShiftOp* x) { + LIRItem value(x->x(), this); + LIRItem count(x->y(), this); + value.load_item(); + LIR_Opr reg = rlock_result(x); + LIR_Opr mcount; + if (count.result()->is_register()) { + mcount = FrameMap::R0_opr; + } else { + mcount = LIR_OprFact::illegalOpr; + } + shift_op(x->op(), reg, value.result(), count.result(), mcount); +} + + +inline bool can_handle_logic_op_as_uimm(ValueType *type, Bytecodes::Code bc) { + jlong int_or_long_const; + if (type->as_IntConstant()) { + int_or_long_const = type->as_IntConstant()->value(); + } else if (type->as_LongConstant()) { + int_or_long_const = type->as_LongConstant()->value(); + } else if (type->as_ObjectConstant()) { + return type->as_ObjectConstant()->value()->is_null_object(); + } else { + return false; + } + + if (Assembler::is_uimm(int_or_long_const, 16)) return true; + if ((int_or_long_const & 0xFFFF) == 0 && + Assembler::is_uimm((jlong)((julong)int_or_long_const >> 16), 16)) return true; + + // see Assembler::andi + if (bc == Bytecodes::_iand && + (is_power_of_2_long(int_or_long_const+1) || + is_power_of_2_long(int_or_long_const) || + is_power_of_2_long(-int_or_long_const))) return true; + if (bc == Bytecodes::_land && + (is_power_of_2_long(int_or_long_const+1) || + (Assembler::is_uimm(int_or_long_const, 32) && is_power_of_2_long(int_or_long_const)) || + (int_or_long_const != min_jlong && is_power_of_2_long(-int_or_long_const)))) return true; + + // special case: xor -1 + if ((bc == Bytecodes::_ixor || bc == Bytecodes::_lxor) && + int_or_long_const == -1) return true; + return false; +} + + +// _iand, _land, _ior, _lor, _ixor, _lxor +void LIRGenerator::do_LogicOp(LogicOp* x) { + LIRItem left(x->x(), this); + LIRItem right(x->y(), this); + + left.load_item(); + + Value rval = right.value(); + LIR_Opr r = rval->operand(); + ValueType *type = rval->type(); + // Logic instructions use unsigned immediate values. + if (can_handle_logic_op_as_uimm(type, x->op())) { + if (!r->is_constant()) { + r = LIR_OprFact::value_type(type); + rval->set_operand(r); + } + right.set_result(r); + } else { + right.load_item(); + } + + LIR_Opr reg = rlock_result(x); + + logic_op(x->op(), reg, left.result(), right.result()); +} + + +// _lcmp, _fcmpl, _fcmpg, _dcmpl, _dcmpg +void LIRGenerator::do_CompareOp(CompareOp* x) { + LIRItem left(x->x(), this); + LIRItem right(x->y(), this); + left.load_item(); + right.load_item(); + LIR_Opr reg = rlock_result(x); + if (x->x()->type()->is_float_kind()) { + Bytecodes::Code code = x->op(); + __ fcmp2int(left.result(), right.result(), reg, (code == Bytecodes::_fcmpl || code == Bytecodes::_dcmpl)); + } else if (x->x()->type()->tag() == longTag) { + __ lcmp2int(left.result(), right.result(), reg); + } else { + Unimplemented(); + } +} + + +void LIRGenerator::do_CompareAndSwap(Intrinsic* x, ValueType* type) { + assert(x->number_of_arguments() == 4, "wrong type"); + LIRItem obj (x->argument_at(0), this); // object + LIRItem offset(x->argument_at(1), this); // offset of field + LIRItem cmp (x->argument_at(2), this); // Value to compare with field. + LIRItem val (x->argument_at(3), this); // Replace field with val if matches cmp. + + LIR_Opr t1 = LIR_OprFact::illegalOpr; + LIR_Opr t2 = LIR_OprFact::illegalOpr; + LIR_Opr addr = new_pointer_register(); + + // Get address of field. + obj.load_item(); + offset.load_item(); + cmp.load_item(); + val.load_item(); + + __ add(obj.result(), offset.result(), addr); + + // Volatile load may be followed by Unsafe CAS. + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ membar(); // To be safe. Unsafe semantics are unclear. + } else { + __ membar_release(); + } + + if (type == objectType) { // Write-barrier needed for Object fields. + // Only cmp value can get overwritten, no do_load required. + pre_barrier(LIR_OprFact::illegalOpr /* addr */, cmp.result() /* pre_val */, + false /* do_load */, false /* patch */, NULL); + } + + if (type == objectType) { + if (UseCompressedOops) { + t1 = new_register(T_OBJECT); + t2 = new_register(T_OBJECT); + } + __ cas_obj(addr, cmp.result(), val.result(), t1, t2); + } else if (type == intType) { + __ cas_int(addr, cmp.result(), val.result(), t1, t2); + } else if (type == longType) { + __ cas_long(addr, cmp.result(), val.result(), t1, t2); + } else { + ShouldNotReachHere(); + } + // Benerate conditional move of boolean result. + LIR_Opr result = rlock_result(x); + __ cmove(lir_cond_equal, LIR_OprFact::intConst(1), LIR_OprFact::intConst(0), + result, as_BasicType(type)); + if (type == objectType) { // Write-barrier needed for Object fields. + // Precise card mark since could either be object or array. + post_barrier(addr, val.result()); + } +} + + +void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { + switch (x->id()) { + case vmIntrinsics::_dabs: { + assert(x->number_of_arguments() == 1, "wrong type"); + LIRItem value(x->argument_at(0), this); + value.load_item(); + LIR_Opr dst = rlock_result(x); + __ abs(value.result(), dst, LIR_OprFact::illegalOpr); + break; + } + case vmIntrinsics::_dsqrt: { + if (VM_Version::has_fsqrt()) { + assert(x->number_of_arguments() == 1, "wrong type"); + LIRItem value(x->argument_at(0), this); + value.load_item(); + LIR_Opr dst = rlock_result(x); + __ sqrt(value.result(), dst, LIR_OprFact::illegalOpr); + break; + } // else fallthru + } + case vmIntrinsics::_dlog10: // fall through + case vmIntrinsics::_dlog: // fall through + case vmIntrinsics::_dsin: // fall through + case vmIntrinsics::_dtan: // fall through + case vmIntrinsics::_dcos: // fall through + case vmIntrinsics::_dexp: { + assert(x->number_of_arguments() == 1, "wrong type"); + + address runtime_entry = NULL; + switch (x->id()) { + case vmIntrinsics::_dsqrt: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt); + break; + case vmIntrinsics::_dsin: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin); + break; + case vmIntrinsics::_dcos: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos); + break; + case vmIntrinsics::_dtan: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan); + break; + case vmIntrinsics::_dlog: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog); + break; + case vmIntrinsics::_dlog10: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10); + break; + case vmIntrinsics::_dexp: + runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dexp); + break; + default: + ShouldNotReachHere(); + } + + LIR_Opr result = call_runtime(x->argument_at(0), runtime_entry, x->type(), NULL); + set_result(x, result); + break; + } + case vmIntrinsics::_dpow: { + assert(x->number_of_arguments() == 2, "wrong type"); + address runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dpow); + LIR_Opr result = call_runtime(x->argument_at(0), x->argument_at(1), runtime_entry, x->type(), NULL); + set_result(x, result); + break; + } + } +} + + +void LIRGenerator::do_ArrayCopy(Intrinsic* x) { + assert(x->number_of_arguments() == 5, "wrong type"); + + // Make all state_for calls early since they can emit code. + CodeEmitInfo* info = state_for(x, x->state()); + + LIRItem src (x->argument_at(0), this); + LIRItem src_pos (x->argument_at(1), this); + LIRItem dst (x->argument_at(2), this); + LIRItem dst_pos (x->argument_at(3), this); + LIRItem length (x->argument_at(4), this); + + // Load all values in callee_save_registers (C calling convention), + // as this makes the parameter passing to the fast case simpler. + src.load_item_force (FrameMap::R14_oop_opr); + src_pos.load_item_force (FrameMap::R15_opr); + dst.load_item_force (FrameMap::R17_oop_opr); + dst_pos.load_item_force (FrameMap::R18_opr); + length.load_item_force (FrameMap::R19_opr); + LIR_Opr tmp = FrameMap::R20_opr; + + int flags; + ciArrayKlass* expected_type; + arraycopy_helper(x, &flags, &expected_type); + + __ arraycopy(src.result(), src_pos.result(), dst.result(), dst_pos.result(), + length.result(), tmp, + expected_type, flags, info); + set_no_result(x); +} + + +// _i2l, _i2f, _i2d, _l2i, _l2f, _l2d, _f2i, _f2l, _f2d, _d2i, _d2l, _d2f +// _i2b, _i2c, _i2s +void LIRGenerator::do_Convert(Convert* x) { + switch (x->op()) { + + // int -> float: force spill + case Bytecodes::_l2f: { + if (!VM_Version::has_fcfids()) { // fcfids is >= Power7 only + // fcfid+frsp needs fixup code to avoid rounding incompatibility. + address entry = CAST_FROM_FN_PTR(address, SharedRuntime::l2f); + LIR_Opr result = call_runtime(x->value(), entry, x->type(), NULL); + set_result(x, result); + break; + } // else fallthru + } + case Bytecodes::_l2d: { + LIRItem value(x->value(), this); + LIR_Opr reg = rlock_result(x); + value.load_item(); + LIR_Opr tmp = force_to_spill(value.result(), T_DOUBLE); + __ convert(x->op(), tmp, reg); + break; + } + case Bytecodes::_i2f: + case Bytecodes::_i2d: { + LIRItem value(x->value(), this); + LIR_Opr reg = rlock_result(x); + value.load_item(); + // Convert i2l first. + LIR_Opr tmp1 = new_register(T_LONG); + __ convert(Bytecodes::_i2l, value.result(), tmp1); + LIR_Opr tmp2 = force_to_spill(tmp1, T_DOUBLE); + __ convert(x->op(), tmp2, reg); + break; + } + + // float -> int: result will be stored + case Bytecodes::_f2l: + case Bytecodes::_d2l: { + LIRItem value(x->value(), this); + LIR_Opr reg = rlock_result(x); + value.set_destroys_register(); // USE_KILL + value.load_item(); + set_vreg_flag(reg, must_start_in_memory); + __ convert(x->op(), value.result(), reg); + break; + } + case Bytecodes::_f2i: + case Bytecodes::_d2i: { + LIRItem value(x->value(), this); + LIR_Opr reg = rlock_result(x); + value.set_destroys_register(); // USE_KILL + value.load_item(); + // Convert l2i afterwards. + LIR_Opr tmp1 = new_register(T_LONG); + set_vreg_flag(tmp1, must_start_in_memory); + __ convert(x->op(), value.result(), tmp1); + __ convert(Bytecodes::_l2i, tmp1, reg); + break; + } + + // Within same category: just register conversions. + case Bytecodes::_i2b: + case Bytecodes::_i2c: + case Bytecodes::_i2s: + case Bytecodes::_i2l: + case Bytecodes::_l2i: + case Bytecodes::_f2d: + case Bytecodes::_d2f: { + LIRItem value(x->value(), this); + LIR_Opr reg = rlock_result(x); + value.load_item(); + __ convert(x->op(), value.result(), reg); + break; + } + + default: ShouldNotReachHere(); + } +} + + +void LIRGenerator::do_NewInstance(NewInstance* x) { + // This instruction can be deoptimized in the slow path. + const LIR_Opr reg = result_register_for(x->type()); +#ifndef PRODUCT + if (PrintNotLoaded && !x->klass()->is_loaded()) { + tty->print_cr(" ###class not loaded at new bci %d", x->printable_bci()); + } +#endif + CodeEmitInfo* info = state_for(x, x->state()); + LIR_Opr klass_reg = FrameMap::R4_metadata_opr; // Used by slow path (NewInstanceStub). + LIR_Opr tmp1 = FrameMap::R5_oop_opr; + LIR_Opr tmp2 = FrameMap::R6_oop_opr; + LIR_Opr tmp3 = FrameMap::R7_oop_opr; + LIR_Opr tmp4 = FrameMap::R8_oop_opr; + new_instance(reg, x->klass(), x->is_unresolved(), tmp1, tmp2, tmp3, tmp4, klass_reg, info); + + // Must prevent reordering of stores for object initialization + // with stores that publish the new object. + __ membar_storestore(); + LIR_Opr result = rlock_result(x); + __ move(reg, result); +} + + +void LIRGenerator::do_NewTypeArray(NewTypeArray* x) { + // Evaluate state_for early since it may emit code. + CodeEmitInfo* info = state_for(x, x->state()); + + LIRItem length(x->length(), this); + length.load_item(); + + LIR_Opr reg = result_register_for(x->type()); + LIR_Opr klass_reg = FrameMap::R4_metadata_opr; // Used by slow path (NewTypeArrayStub). + // We use R5 in order to get a temp effect. This reg is used in slow path (NewTypeArrayStub). + LIR_Opr tmp1 = FrameMap::R5_oop_opr; + LIR_Opr tmp2 = FrameMap::R6_oop_opr; + LIR_Opr tmp3 = FrameMap::R7_oop_opr; + LIR_Opr tmp4 = FrameMap::R8_oop_opr; + LIR_Opr len = length.result(); + BasicType elem_type = x->elt_type(); + + __ metadata2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg); + + CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info); + __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path); + + // Must prevent reordering of stores for object initialization + // with stores that publish the new object. + __ membar_storestore(); + LIR_Opr result = rlock_result(x); + __ move(reg, result); +} + + +void LIRGenerator::do_NewObjectArray(NewObjectArray* x) { + // Evaluate state_for early since it may emit code. + CodeEmitInfo* info = state_for(x, x->state()); + // In case of patching (i.e., object class is not yet loaded), + // we need to reexecute the instruction and therefore provide + // the state before the parameters have been consumed. + CodeEmitInfo* patching_info = NULL; + if (!x->klass()->is_loaded() || PatchALot) { + patching_info = state_for(x, x->state_before()); + } + + LIRItem length(x->length(), this); + length.load_item(); + + const LIR_Opr reg = result_register_for(x->type()); + LIR_Opr klass_reg = FrameMap::R4_metadata_opr; // Used by slow path (NewObjectArrayStub). + // We use R5 in order to get a temp effect. This reg is used in slow path (NewObjectArrayStub). + LIR_Opr tmp1 = FrameMap::R5_oop_opr; + LIR_Opr tmp2 = FrameMap::R6_oop_opr; + LIR_Opr tmp3 = FrameMap::R7_oop_opr; + LIR_Opr tmp4 = FrameMap::R8_oop_opr; + LIR_Opr len = length.result(); + + CodeStub* slow_path = new NewObjectArrayStub(klass_reg, len, reg, info); + ciMetadata* obj = ciObjArrayKlass::make(x->klass()); + if (obj == ciEnv::unloaded_ciobjarrayklass()) { + BAILOUT("encountered unloaded_ciobjarrayklass due to out of memory error"); + } + klass2reg_with_patching(klass_reg, obj, patching_info); + __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, T_OBJECT, klass_reg, slow_path); + + // Must prevent reordering of stores for object initialization + // with stores that publish the new object. + __ membar_storestore(); + LIR_Opr result = rlock_result(x); + __ move(reg, result); +} + + +void LIRGenerator::do_NewMultiArray(NewMultiArray* x) { + Values* dims = x->dims(); + int i = dims->length(); + LIRItemList* items = new LIRItemList(dims->length(), NULL); + while (i-- > 0) { + LIRItem* size = new LIRItem(dims->at(i), this); + items->at_put(i, size); + } + + // Evaluate state_for early since it may emit code. + CodeEmitInfo* patching_info = NULL; + if (!x->klass()->is_loaded() || PatchALot) { + patching_info = state_for(x, x->state_before()); + + // Cannot re-use same xhandlers for multiple CodeEmitInfos, so + // clone all handlers (NOTE: Usually this is handled transparently + // by the CodeEmitInfo cloning logic in CodeStub constructors but + // is done explicitly here because a stub isn't being used). + x->set_exception_handlers(new XHandlers(x->exception_handlers())); + } + CodeEmitInfo* info = state_for(x, x->state()); + + i = dims->length(); + while (i-- > 0) { + LIRItem* size = items->at(i); + size->load_nonconstant(); + // FrameMap::_reserved_argument_area_size includes the dimensions + // varargs, because it's initialized to hir()->max_stack() when the + // FrameMap is created. + store_stack_parameter(size->result(), in_ByteSize(i*sizeof(jint) + FrameMap::first_available_sp_in_frame)); + } + + const LIR_Opr klass_reg = FrameMap::R4_metadata_opr; // Used by slow path. + klass2reg_with_patching(klass_reg, x->klass(), patching_info); + + LIR_Opr rank = FrameMap::R5_opr; // Used by slow path. + __ move(LIR_OprFact::intConst(x->rank()), rank); + + LIR_Opr varargs = FrameMap::as_pointer_opr(R6); // Used by slow path. + __ leal(LIR_OprFact::address(new LIR_Address(FrameMap::SP_opr, FrameMap::first_available_sp_in_frame, T_INT)), + varargs); + + // Note: This instruction can be deoptimized in the slow path. + LIR_OprList* args = new LIR_OprList(3); + args->append(klass_reg); + args->append(rank); + args->append(varargs); + const LIR_Opr reg = result_register_for(x->type()); + __ call_runtime(Runtime1::entry_for(Runtime1::new_multi_array_id), + LIR_OprFact::illegalOpr, + reg, args, info); + + // Must prevent reordering of stores for object initialization + // with stores that publish the new object. + __ membar_storestore(); + LIR_Opr result = rlock_result(x); + __ move(reg, result); +} + + +void LIRGenerator::do_BlockBegin(BlockBegin* x) { + // nothing to do for now +} + + +void LIRGenerator::do_CheckCast(CheckCast* x) { + LIRItem obj(x->obj(), this); + CodeEmitInfo* patching_info = NULL; + if (!x->klass()->is_loaded() || (PatchALot && !x->is_incompatible_class_change_check())) { + // Must do this before locking the destination register as + // an oop register, and before the obj is loaded (so x->obj()->item() + // is valid for creating a debug info location). + patching_info = state_for(x, x->state_before()); + } + obj.load_item(); + LIR_Opr out_reg = rlock_result(x); + CodeStub* stub; + CodeEmitInfo* info_for_exception = state_for(x); + + if (x->is_incompatible_class_change_check()) { + assert(patching_info == NULL, "can't patch this"); + stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, + LIR_OprFact::illegalOpr, info_for_exception); + } else { + stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception); + } + // Following registers are used by slow_subtype_check: + LIR_Opr tmp1 = FrameMap::R4_oop_opr; // super_klass + LIR_Opr tmp2 = FrameMap::R5_oop_opr; // sub_klass + LIR_Opr tmp3 = FrameMap::R6_oop_opr; // temp + __ checkcast(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3, + x->direct_compare(), info_for_exception, patching_info, stub, + x->profiled_method(), x->profiled_bci()); +} + + +void LIRGenerator::do_InstanceOf(InstanceOf* x) { + LIRItem obj(x->obj(), this); + CodeEmitInfo* patching_info = NULL; + if (!x->klass()->is_loaded() || PatchALot) { + patching_info = state_for(x, x->state_before()); + } + // Ensure the result register is not the input register because the + // result is initialized before the patching safepoint. + obj.load_item(); + LIR_Opr out_reg = rlock_result(x); + // Following registers are used by slow_subtype_check: + LIR_Opr tmp1 = FrameMap::R4_oop_opr; // super_klass + LIR_Opr tmp2 = FrameMap::R5_oop_opr; // sub_klass + LIR_Opr tmp3 = FrameMap::R6_oop_opr; // temp + __ instanceof(out_reg, obj.result(), x->klass(), tmp1, tmp2, tmp3, + x->direct_compare(), patching_info, + x->profiled_method(), x->profiled_bci()); +} + + +void LIRGenerator::do_If(If* x) { + assert(x->number_of_sux() == 2, "inconsistency"); + ValueTag tag = x->x()->type()->tag(); + LIRItem xitem(x->x(), this); + LIRItem yitem(x->y(), this); + LIRItem* xin = &xitem; + LIRItem* yin = &yitem; + If::Condition cond = x->cond(); + + LIR_Opr left = LIR_OprFact::illegalOpr; + LIR_Opr right = LIR_OprFact::illegalOpr; + + xin->load_item(); + left = xin->result(); + + if (yin->result()->is_constant() && yin->result()->type() == T_INT && + Assembler::is_simm16(yin->result()->as_constant_ptr()->as_jint())) { + // Inline int constants which are small enough to be immediate operands. + right = LIR_OprFact::value_type(yin->value()->type()); + } else if (tag == longTag && yin->is_constant() && yin->get_jlong_constant() == 0 && + (cond == If::eql || cond == If::neq)) { + // Inline long zero. + right = LIR_OprFact::value_type(yin->value()->type()); + } else if (tag == objectTag && yin->is_constant() && (yin->get_jobject_constant()->is_null_object())) { + right = LIR_OprFact::value_type(yin->value()->type()); + } else { + yin->load_item(); + right = yin->result(); + } + set_no_result(x); + + // Add safepoint before generating condition code so it can be recomputed. + if (x->is_safepoint()) { + // Increment backedge counter if needed. + increment_backedge_counter(state_for(x, x->state_before()), x->profiled_bci()); + __ safepoint(safepoint_poll_register(), state_for(x, x->state_before())); + } + + __ cmp(lir_cond(cond), left, right); + // Generate branch profiling. Profiling code doesn't kill flags. + profile_branch(x, cond); + move_to_phi(x->state()); + if (x->x()->type()->is_float_kind()) { + __ branch(lir_cond(cond), right->type(), x->tsux(), x->usux()); + } else { + __ branch(lir_cond(cond), right->type(), x->tsux()); + } + assert(x->default_sux() == x->fsux(), "wrong destination above"); + __ jump(x->default_sux()); +} + + +LIR_Opr LIRGenerator::getThreadPointer() { + return FrameMap::as_pointer_opr(R16_thread); +} + + +void LIRGenerator::trace_block_entry(BlockBegin* block) { + LIR_Opr arg1 = FrameMap::R3_opr; // ARG1 + __ move(LIR_OprFact::intConst(block->block_id()), arg1); + LIR_OprList* args = new LIR_OprList(1); + args->append(arg1); + address func = CAST_FROM_FN_PTR(address, Runtime1::trace_block_entry); + __ call_runtime_leaf(func, LIR_OprFact::illegalOpr, LIR_OprFact::illegalOpr, args); +} + + +void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address, + CodeEmitInfo* info) { +#ifdef _LP64 + __ store(value, address, info); +#else + Unimplemented(); +// __ volatile_store_mem_reg(value, address, info); +#endif +} + +void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, + CodeEmitInfo* info) { +#ifdef _LP64 + __ load(address, result, info); +#else + Unimplemented(); +// __ volatile_load_mem_reg(address, result, info); +#endif +} + + +void LIRGenerator::put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data, + BasicType type, bool is_volatile) { + LIR_Opr base_op = src; + LIR_Opr index_op = offset; + + bool is_obj = (type == T_ARRAY || type == T_OBJECT); +#ifndef _LP64 + if (is_volatile && type == T_LONG) { + __ volatile_store_unsafe_reg(data, src, offset, type, NULL, lir_patch_none); + } else +#endif + { + if (type == T_BOOLEAN) { + type = T_BYTE; + } + LIR_Address* addr; + if (type == T_ARRAY || type == T_OBJECT) { + LIR_Opr tmp = new_pointer_register(); + __ add(base_op, index_op, tmp); + addr = new LIR_Address(tmp, type); + } else { + addr = new LIR_Address(base_op, index_op, type); + } + + if (is_obj) { + pre_barrier(LIR_OprFact::address(addr), LIR_OprFact::illegalOpr /* pre_val */, + true /* do_load */, false /* patch */, NULL); + // _bs->c1_write_barrier_pre(this, LIR_OprFact::address(addr)); + } + __ move(data, addr); + if (is_obj) { + // This address is precise. + post_barrier(LIR_OprFact::address(addr), data); + } + } +} + + +void LIRGenerator::get_Object_unsafe(LIR_Opr dst, LIR_Opr src, LIR_Opr offset, + BasicType type, bool is_volatile) { +#ifndef _LP64 + if (is_volatile && type == T_LONG) { + __ volatile_load_unsafe_reg(src, offset, dst, type, NULL, lir_patch_none); + } else +#endif + { + LIR_Address* addr = new LIR_Address(src, offset, type); + __ load(addr, dst); + } +} + + +void LIRGenerator::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { + BasicType type = x->basic_type(); + LIRItem src(x->object(), this); + LIRItem off(x->offset(), this); + LIRItem value(x->value(), this); + + src.load_item(); + value.load_item(); + off.load_nonconstant(); + + LIR_Opr dst = rlock_result(x, type); + LIR_Opr data = value.result(); + bool is_obj = (type == T_ARRAY || type == T_OBJECT); + + LIR_Opr tmp = FrameMap::R0_opr; + LIR_Opr ptr = new_pointer_register(); + __ add(src.result(), off.result(), ptr); + + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ membar(); + } else { + __ membar_release(); + } + + if (x->is_add()) { + __ xadd(ptr, data, dst, tmp); + } else { + const bool can_move_barrier = true; // TODO: port GraphKit::can_move_pre_barrier() from C2 + if (!can_move_barrier && is_obj) { + // Do the pre-write barrier, if any. + pre_barrier(ptr, LIR_OprFact::illegalOpr /* pre_val */, + true /* do_load */, false /* patch */, NULL); + } + __ xchg(ptr, data, dst, tmp); + if (is_obj) { + // Seems to be a precise address. + post_barrier(ptr, data); + if (can_move_barrier) { + pre_barrier(LIR_OprFact::illegalOpr, dst /* pre_val */, + false /* do_load */, false /* patch */, NULL); + } + } + } + + __ membar(); +} + + +void LIRGenerator::do_update_CRC32(Intrinsic* x) { + assert(UseCRC32Intrinsics, "or should not be here"); + LIR_Opr result = rlock_result(x); + + switch (x->id()) { + case vmIntrinsics::_updateCRC32: { + LIRItem crc(x->argument_at(0), this); + LIRItem val(x->argument_at(1), this); + // Registers destroyed by update_crc32. + crc.set_destroys_register(); + val.set_destroys_register(); + crc.load_item(); + val.load_item(); + __ update_crc32(crc.result(), val.result(), result); + break; + } + case vmIntrinsics::_updateBytesCRC32: + case vmIntrinsics::_updateByteBufferCRC32: { + bool is_updateBytes = (x->id() == vmIntrinsics::_updateBytesCRC32); + + LIRItem crc(x->argument_at(0), this); + LIRItem buf(x->argument_at(1), this); + LIRItem off(x->argument_at(2), this); + LIRItem len(x->argument_at(3), this); + buf.load_item(); + off.load_nonconstant(); + + LIR_Opr index = off.result(); + int offset = is_updateBytes ? arrayOopDesc::base_offset_in_bytes(T_BYTE) : 0; + if (off.result()->is_constant()) { + index = LIR_OprFact::illegalOpr; + offset += off.result()->as_jint(); + } + LIR_Opr base_op = buf.result(); + LIR_Address* a = NULL; + + if (index->is_valid()) { + LIR_Opr tmp = new_register(T_LONG); + __ convert(Bytecodes::_i2l, index, tmp); + index = tmp; + __ add(index, LIR_OprFact::intptrConst(offset), index); + a = new LIR_Address(base_op, index, T_BYTE); + } else { + a = new LIR_Address(base_op, offset, T_BYTE); + } + + BasicTypeList signature(3); + signature.append(T_INT); + signature.append(T_ADDRESS); + signature.append(T_INT); + CallingConvention* cc = frame_map()->c_calling_convention(&signature); + const LIR_Opr result_reg = result_register_for(x->type()); + + LIR_Opr arg1 = cc->at(0), + arg2 = cc->at(1), + arg3 = cc->at(2); + + // CCallingConventionRequiresIntsAsLongs + crc.load_item_force(arg1); // We skip int->long conversion here, because CRC32 stub doesn't care about high bits. + __ leal(LIR_OprFact::address(a), arg2); + load_int_as_long(gen()->lir(), len, arg3); + + __ call_runtime_leaf(StubRoutines::updateBytesCRC32(), LIR_OprFact::illegalOpr, result_reg, cc->args()); + __ move(result_reg, result); + break; + } + default: { + ShouldNotReachHere(); + } + } +} diff --git a/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.cpp new file mode 100644 index 00000000000..7c73b1c70a8 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 "c1/c1_Instruction.hpp" +#include "c1/c1_LinearScan.hpp" +#include "utilities/bitMap.inline.hpp" + +void LinearScan::allocate_fpu_stack() { + Unimplemented(); + // No FPU stack on PPC +} diff --git a/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.hpp new file mode 100644 index 00000000000..d0f6002929e --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_LinearScan_ppc.hpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 CPU_PPC_VM_C1_LINEARSCAN_PPC_HPP +#define CPU_PPC_VM_C1_LINEARSCAN_PPC_HPP + +inline bool LinearScan::is_processed_reg_num(int reg_num) { + assert(FrameMap::R0_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 1, "wrong assumption below"); + assert(FrameMap::R1_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 2, "wrong assumption below"); + assert(FrameMap::R13_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 3, "wrong assumption below"); + assert(FrameMap::R16_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 4, "wrong assumption below"); + assert(FrameMap::R29_opr->cpu_regnr() == FrameMap::last_cpu_reg() + 5, "wrong assumption below"); + return reg_num <= FrameMap::last_cpu_reg() || reg_num >= pd_nof_cpu_regs_frame_map; +} + +inline int LinearScan::num_physical_regs(BasicType type) { + return 1; +} + + +inline bool LinearScan::requires_adjacent_regs(BasicType type) { + return false; +} + +inline bool LinearScan::is_caller_save(int assigned_reg) { + return true; // assigned_reg < pd_first_callee_saved_reg; +} + + +inline void LinearScan::pd_add_temps(LIR_Op* op) { + // No special case behaviours yet +} + + +inline bool LinearScanWalker::pd_init_regs_for_alloc(Interval* cur) { + if (allocator()->gen()->is_vreg_flag_set(cur->reg_num(), LIRGenerator::callee_saved)) { + assert(cur->type() != T_FLOAT && cur->type() != T_DOUBLE, "cpu regs only"); + _first_reg = pd_first_callee_saved_reg; + _last_reg = pd_last_callee_saved_reg; + ShouldNotReachHere(); // Currently no callee saved regs. + return true; + } else if (cur->type() == T_INT || cur->type() == T_LONG || cur->type() == T_OBJECT || + cur->type() == T_ADDRESS || cur->type() == T_METADATA) { + _first_reg = pd_first_cpu_reg; + _last_reg = pd_last_cpu_reg; + return true; + } + return false; +} + +#endif // CPU_PPC_VM_C1_LINEARSCAN_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp new file mode 100644 index 00000000000..f41a83b1c71 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.cpp @@ -0,0 +1,486 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "classfile/systemDictionary.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "interpreter/interpreter.hpp" +#include "oops/arrayOop.hpp" +#include "oops/markOop.hpp" +#include "runtime/basicLock.hpp" +#include "runtime/biasedLocking.hpp" +#include "runtime/os.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/sharedRuntime.hpp" + + +void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache) { + const Register temp_reg = R12_scratch2; + verify_oop(receiver); + load_klass(temp_reg, receiver); + if (TrapBasedICMissChecks) { + trap_ic_miss_check(temp_reg, iCache); + } else { + Label L; + cmpd(CCR0, temp_reg, iCache); + beq(CCR0, L); + //load_const_optimized(temp_reg, SharedRuntime::get_ic_miss_stub(), R0); + calculate_address_from_global_toc(temp_reg, SharedRuntime::get_ic_miss_stub(), true, true, false); + mtctr(temp_reg); + bctr(); + align(32, 12); + bind(L); + } +} + + +void C1_MacroAssembler::explicit_null_check(Register base) { + Unimplemented(); +} + + +void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_bytes) { + assert(bang_size_in_bytes >= frame_size_in_bytes, "stack bang size incorrect"); + // Make sure there is enough stack space for this method's activation. + generate_stack_overflow_check(bang_size_in_bytes); + + // Create the frame. + const Register return_pc = R0; + + mflr(return_pc); + // Get callers sp. + std(return_pc, _abi(lr), R1_SP); // SP->lr = return_pc + push_frame(frame_size_in_bytes, R0); // SP -= frame_size_in_bytes +} + + +void C1_MacroAssembler::unverified_entry(Register receiver, Register ic_klass) { + Unimplemented(); // Currently unused. + //if (C1Breakpoint) illtrap(); + //inline_cache_check(receiver, ic_klass); +} + + +void C1_MacroAssembler::verified_entry() { + if (C1Breakpoint) illtrap(); + // build frame +} + + +void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox, Register Rscratch, Label& slow_case) { + assert_different_registers(Rmark, Roop, Rbox, Rscratch); + + Label done, cas_failed, slow_int; + + // The following move must be the first instruction of emitted since debug + // information may be generated for it. + // Load object header. + ld(Rmark, oopDesc::mark_offset_in_bytes(), Roop); + + verify_oop(Roop); + + // Save object being locked into the BasicObjectLock... + std(Roop, BasicObjectLock::obj_offset_in_bytes(), Rbox); + + if (UseBiasedLocking) { + biased_locking_enter(CCR0, Roop, Rmark, Rscratch, R0, done, &slow_int); + } + + // ... and mark it unlocked. + ori(Rmark, Rmark, markOopDesc::unlocked_value); + + // Save unlocked object header into the displaced header location on the stack. + std(Rmark, BasicLock::displaced_header_offset_in_bytes(), Rbox); + + // Compare object markOop with Rmark and if equal exchange Rscratch with object markOop. + assert(oopDesc::mark_offset_in_bytes() == 0, "cas must take a zero displacement"); + cmpxchgd(/*flag=*/CCR0, + /*current_value=*/Rscratch, + /*compare_value=*/Rmark, + /*exchange_value=*/Rbox, + /*where=*/Roop/*+0==mark_offset_in_bytes*/, + MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, + MacroAssembler::cmpxchgx_hint_acquire_lock(), + noreg, + &cas_failed, + /*check without membar and ldarx first*/true); + // If compare/exchange succeeded we found an unlocked object and we now have locked it + // hence we are done. + b(done); + + bind(slow_int); + b(slow_case); // far + + bind(cas_failed); + // We did not find an unlocked object so see if this is a recursive case. + sub(Rscratch, Rscratch, R1_SP); + load_const_optimized(R0, (~(os::vm_page_size()-1) | markOopDesc::lock_mask_in_place)); + and_(R0/*==0?*/, Rscratch, R0); + std(R0/*==0, perhaps*/, BasicLock::displaced_header_offset_in_bytes(), Rbox); + bne(CCR0, slow_int); + + bind(done); +} + + +void C1_MacroAssembler::unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case) { + assert_different_registers(Rmark, Roop, Rbox); + + Label slow_int, done; + + Address mark_addr(Roop, oopDesc::mark_offset_in_bytes()); + assert(mark_addr.disp() == 0, "cas must take a zero displacement"); + + if (UseBiasedLocking) { + // Load the object out of the BasicObjectLock. + ld(Roop, BasicObjectLock::obj_offset_in_bytes(), Rbox); + verify_oop(Roop); + biased_locking_exit(CCR0, Roop, R0, done); + } + // Test first it it is a fast recursive unlock. + ld(Rmark, BasicLock::displaced_header_offset_in_bytes(), Rbox); + cmpdi(CCR0, Rmark, 0); + beq(CCR0, done); + if (!UseBiasedLocking) { + // Load object. + ld(Roop, BasicObjectLock::obj_offset_in_bytes(), Rbox); + verify_oop(Roop); + } + + // Check if it is still a light weight lock, this is is true if we see + // the stack address of the basicLock in the markOop of the object. + cmpxchgd(/*flag=*/CCR0, + /*current_value=*/R0, + /*compare_value=*/Rbox, + /*exchange_value=*/Rmark, + /*where=*/Roop, + MacroAssembler::MemBarRel, + MacroAssembler::cmpxchgx_hint_release_lock(), + noreg, + &slow_int); + b(done); + bind(slow_int); + b(slow_case); // far + + // Done + bind(done); +} + + +void C1_MacroAssembler::try_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register, must be global register for incr_allocated_bytes + Register t2, // temp register + Label& slow_case // continuation point if fast allocation fails +) { + if (UseTLAB) { + tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, slow_case); + } else { + eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); + RegisterOrConstant size_in_bytes = var_size_in_bytes->is_valid() + ? RegisterOrConstant(var_size_in_bytes) + : RegisterOrConstant(con_size_in_bytes); + incr_allocated_bytes(size_in_bytes, t1, t2); + } +} + + +void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register t1, Register t2) { + assert_different_registers(obj, klass, len, t1, t2); + if (UseBiasedLocking && !len->is_valid()) { + ld(t1, in_bytes(Klass::prototype_header_offset()), klass); + } else { + load_const_optimized(t1, (intx)markOopDesc::prototype()); + } + std(t1, oopDesc::mark_offset_in_bytes(), obj); + store_klass(obj, klass); + if (len->is_valid()) { + stw(len, arrayOopDesc::length_offset_in_bytes(), obj); + } else if (UseCompressedClassPointers) { + // Otherwise length is in the class gap. + store_klass_gap(obj); + } +} + + +void C1_MacroAssembler::initialize_body(Register base, Register index) { + assert_different_registers(base, index); + srdi(index, index, LogBytesPerWord); + clear_memory_doubleword(base, index); +} + +void C1_MacroAssembler::initialize_body(Register obj, Register tmp1, Register tmp2, + int obj_size_in_bytes, int hdr_size_in_bytes) { + const int index = (obj_size_in_bytes - hdr_size_in_bytes) / HeapWordSize; + + const int cl_size = VM_Version::L1_data_cache_line_size(), + cl_dwords = cl_size>>3, + cl_dw_addr_bits = exact_log2(cl_dwords); + + const Register tmp = R0, + base_ptr = tmp1, + cnt_dwords = tmp2; + + if (index <= 6) { + // Use explicit NULL stores. + if (index > 0) { li(tmp, 0); } + for (int i = 0; i < index; ++i) { std(tmp, hdr_size_in_bytes + i * HeapWordSize, obj); } + + } else if (index < (2<0). + andi(cnt_dwords, cnt_dwords, cl_dwords-1); // Rest in dwords. + mtctr(tmp); // Load counter. + + bind(fastloop); + dcbz(base_ptr); // Clear 128byte aligned block. + addi(base_ptr, base_ptr, cl_size); + bdnz(fastloop); + + cmpdi(CCR0, cnt_dwords, 0); // size 0? + beq(CCR0, done); // rest == 0 + li(tmp, 0); + mtctr(cnt_dwords); // Load counter. + + bind(restloop); // Clear rest. + std(tmp, 0, base_ptr); // Clear 8byte aligned block. + addi(base_ptr, base_ptr, 8); + bdnz(restloop); + + bind(done); + } +} + +void C1_MacroAssembler::allocate_object( + Register obj, // result: pointer to object after successful allocation + Register t1, // temp register + Register t2, // temp register + Register t3, // temp register + int hdr_size, // object header size in words + int obj_size, // object size in words + Register klass, // object klass + Label& slow_case // continuation point if fast allocation fails +) { + assert_different_registers(obj, t1, t2, t3, klass); + + // allocate space & initialize header + if (!is_simm16(obj_size * wordSize)) { + // Would need to use extra register to load + // object size => go the slow case for now. + b(slow_case); + return; + } + try_allocate(obj, noreg, obj_size * wordSize, t2, t3, slow_case); + + initialize_object(obj, klass, noreg, obj_size * HeapWordSize, t1, t2); +} + +void C1_MacroAssembler::initialize_object( + Register obj, // result: pointer to object after successful allocation + Register klass, // object klass + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Register t2 // temp register + ) { + const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize; + + initialize_header(obj, klass, noreg, t1, t2); + +#ifdef ASSERT + { + lwz(t1, in_bytes(Klass::layout_helper_offset()), klass); + if (var_size_in_bytes != noreg) { + cmpw(CCR0, t1, var_size_in_bytes); + } else { + cmpwi(CCR0, t1, con_size_in_bytes); + } + asm_assert_eq("bad size in initialize_object", 0x753); + } +#endif + + // Initialize body. + if (var_size_in_bytes != noreg) { + // Use a loop. + addi(t1, obj, hdr_size_in_bytes); // Compute address of first element. + addi(t2, var_size_in_bytes, -hdr_size_in_bytes); // Compute size of body. + initialize_body(t1, t2); + } else if (con_size_in_bytes > hdr_size_in_bytes) { + // Use a loop. + initialize_body(obj, t1, t2, con_size_in_bytes, hdr_size_in_bytes); + } + + if (CURRENT_ENV->dtrace_alloc_probes()) { + Unimplemented(); +// assert(obj == O0, "must be"); +// call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)), +// relocInfo::runtime_call_type); + } + + verify_oop(obj); +} + + +void C1_MacroAssembler::allocate_array( + Register obj, // result: pointer to array after successful allocation + Register len, // array length + Register t1, // temp register + Register t2, // temp register + Register t3, // temp register + int hdr_size, // object header size in words + int elt_size, // element size in bytes + Register klass, // object klass + Label& slow_case // continuation point if fast allocation fails +) { + assert_different_registers(obj, len, t1, t2, t3, klass); + + // Determine alignment mask. + assert(!(BytesPerWord & 1), "must be a multiple of 2 for masking code to work"); + int log2_elt_size = exact_log2(elt_size); + + // Check for negative or excessive length. + size_t max_length = max_array_allocation_length >> log2_elt_size; + if (UseTLAB) { + size_t max_tlab = align_size_up(ThreadLocalAllocBuffer::max_size() >> log2_elt_size, 64*K); + if (max_tlab < max_length) { max_length = max_tlab; } + } + load_const_optimized(t1, max_length); + cmpld(CCR0, len, t1); + bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CCR0, Assembler::greater), slow_case); + + // compute array size + // note: If 0 <= len <= max_length, len*elt_size + header + alignment is + // smaller or equal to the largest integer; also, since top is always + // aligned, we can do the alignment here instead of at the end address + // computation. + const Register arr_size = t1; + Register arr_len_in_bytes = len; + if (elt_size != 1) { + sldi(t1, len, log2_elt_size); + arr_len_in_bytes = t1; + } + addi(arr_size, arr_len_in_bytes, hdr_size * wordSize + MinObjAlignmentInBytesMask); // Add space for header & alignment. + clrrdi(arr_size, arr_size, LogMinObjAlignmentInBytes); // Align array size. + + // Allocate space & initialize header. + if (UseTLAB) { + tlab_allocate(obj, arr_size, 0, t2, slow_case); + } else { + eden_allocate(obj, arr_size, 0, t2, t3, slow_case); + } + initialize_header(obj, klass, len, t2, t3); + + // Initialize body. + const Register base = t2; + const Register index = t3; + addi(base, obj, hdr_size * wordSize); // compute address of first element + addi(index, arr_size, -(hdr_size * wordSize)); // compute index = number of bytes to clear + initialize_body(base, index); + + if (CURRENT_ENV->dtrace_alloc_probes()) { + Unimplemented(); + //assert(obj == O0, "must be"); + //call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)), + // relocInfo::runtime_call_type); + } + + verify_oop(obj); +} + + +#ifndef PRODUCT + +void C1_MacroAssembler::verify_stack_oop(int stack_offset) { + verify_oop_addr((RegisterOrConstant)(stack_offset + STACK_BIAS), R1_SP, "broken oop in stack slot"); +} + +void C1_MacroAssembler::verify_not_null_oop(Register r) { + Label not_null; + cmpdi(CCR0, r, 0); + bne(CCR0, not_null); + stop("non-null oop required"); + bind(not_null); + if (!VerifyOops) return; + verify_oop(r); +} + +#endif // PRODUCT + +void C1_MacroAssembler::null_check(Register r, Label* Lnull) { + if (TrapBasedNullChecks) { // SIGTRAP based + trap_null_check(r); + } else { // explicit + //const address exception_entry = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id); + assert(Lnull != NULL, "must have Label for explicit check"); + cmpdi(CCR0, r, 0); + bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CCR0, Assembler::equal), *Lnull); + } +} + +address C1_MacroAssembler::call_c_with_frame_resize(address dest, int frame_resize) { + if (frame_resize) { resize_frame(-frame_resize, R0); } +#if defined(ABI_ELFv2) + address return_pc = call_c(dest, relocInfo::runtime_call_type); +#else + address return_pc = call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, dest), relocInfo::runtime_call_type); +#endif + if (frame_resize) { resize_frame(frame_resize, R0); } + return return_pc; +} diff --git a/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.hpp new file mode 100644 index 00000000000..9989baa8700 --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_MacroAssembler_ppc.hpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 CPU_PPC_VM_C1_MACROASSEMBLER_PPC_HPP +#define CPU_PPC_VM_C1_MACROASSEMBLER_PPC_HPP + + void pd_init() { /* nothing to do */ } + + public: + void try_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Register t2, // temp register + Label& slow_case // continuation point if fast allocation fails + ); + + void initialize_header(Register obj, Register klass, Register len, Register t1, Register t2); + void initialize_body(Register base, Register index); + void initialize_body(Register obj, Register tmp1, Register tmp2, int obj_size_in_bytes, int hdr_size_in_bytes); + + // locking/unlocking + void lock_object (Register Rmark, Register Roop, Register Rbox, Register Rscratch, Label& slow_case); + void unlock_object(Register Rmark, Register Roop, Register Rbox, Label& slow_case); + + void initialize_object( + Register obj, // result: pointer to object after successful allocation + Register klass, // object klass + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Register t2 // temp register + ); + + // Allocation of fixed-size objects + // (Can also be used to allocate fixed-size arrays, by setting + // hdr_size correctly and storing the array length afterwards.) + void allocate_object( + Register obj, // result: pointer to object after successful allocation + Register t1, // temp register + Register t2, // temp register + Register t3, // temp register + int hdr_size, // object header size in words + int obj_size, // object size in words + Register klass, // object klass + Label& slow_case // continuation point if fast allocation fails + ); + + enum { + max_array_allocation_length = 0x40000000 // ppc friendly value, requires lis only + }; + + // Allocation of arrays + void allocate_array( + Register obj, // result: pointer to array after successful allocation + Register len, // array length + Register t1, // temp register + Register t2, // temp register + Register t3, // temp register + int hdr_size, // object header size in words + int elt_size, // element size in bytes + Register klass, // object klass + Label& slow_case // continuation point if fast allocation fails + ); + + void null_check(Register r, Label *Lnull = NULL); + + address call_c_with_frame_resize(address dest, int frame_resize); + +#endif // CPU_PPC_VM_C1_MACROASSEMBLER_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp b/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp new file mode 100644 index 00000000000..5fbaa4beb4e --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_Runtime1_ppc.cpp @@ -0,0 +1,1020 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 "c1/c1_Defs.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "interpreter/interpreter.hpp" +#include "nativeInst_ppc.hpp" +#include "oops/compiledICHolder.hpp" +#include "oops/oop.inline.hpp" +#include "prims/jvmtiExport.hpp" +#include "register_ppc.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/signature.hpp" +#include "runtime/vframeArray.hpp" +#include "utilities/macros.hpp" +#include "vmreg_ppc.inline.hpp" +#if INCLUDE_ALL_GCS +#include "gc/g1/g1SATBCardTableModRefBS.hpp" +#endif + +// Implementation of StubAssembler + +int StubAssembler::call_RT(Register oop_result1, Register metadata_result, + address entry_point, int number_of_arguments) { + set_num_rt_args(0); // Nothing on stack + assert(!(oop_result1->is_valid() || metadata_result->is_valid()) || + oop_result1 != metadata_result, "registers must be different"); + + // Currently no stack banging. We assume that there are enough + // StackShadowPages (which have been banged in generate_stack_overflow_check) + // for the stub frame and the runtime frames. + + set_last_Java_frame(R1_SP, noreg); + + // ARG1 must hold thread address. + mr(R3_ARG1, R16_thread); + + address return_pc = call_c_with_frame_resize(entry_point, /*No resize, we have a C compatible frame.*/0); + + reset_last_Java_frame(); + + // Check for pending exceptions. + { + ld(R0, in_bytes(Thread::pending_exception_offset()), R16_thread); + cmpdi(CCR0, R0, 0); + + // This used to conditionally jump to forward_exception however it is + // possible if we relocate that the branch will not reach. So we must jump + // around so we can always reach. + + Label ok; + beq(CCR0, ok); + + // Make sure that the vm_results are cleared. + if (oop_result1->is_valid() || metadata_result->is_valid()) { + li(R0, 0); + if (oop_result1->is_valid()) { + std(R0, in_bytes(JavaThread::vm_result_offset()), R16_thread); + } + if (metadata_result->is_valid()) { + std(R0, in_bytes(JavaThread::vm_result_2_offset()), R16_thread); + } + } + + if (frame_size() == no_frame_size) { + ShouldNotReachHere(); // We always have a frame size. + //pop_frame(); // pop the stub frame + //ld(R0, _abi(lr), R1_SP); + //mtlr(R0); + //load_const_optimized(R0, StubRoutines::forward_exception_entry()); + //mtctr(R0); + //bctr(); + } else if (_stub_id == Runtime1::forward_exception_id) { + should_not_reach_here(); + } else { + // keep stub frame for next call_RT + //load_const_optimized(R0, Runtime1::entry_for(Runtime1::forward_exception_id)); + add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(Runtime1::entry_for(Runtime1::forward_exception_id))); + mtctr(R0); + bctr(); + } + + bind(ok); + } + + // Get oop results if there are any and reset the values in the thread. + if (oop_result1->is_valid()) { + get_vm_result(oop_result1); + } + if (metadata_result->is_valid()) { + get_vm_result_2(metadata_result); + } + + return (int)(return_pc - code_section()->start()); +} + + +int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1) { + mr_if_needed(R4_ARG2, arg1); + return call_RT(oop_result1, metadata_result, entry, 1); +} + + +int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2) { + mr_if_needed(R4_ARG2, arg1); + mr_if_needed(R5_ARG3, arg2); assert(arg2 != R4_ARG2, "smashed argument"); + return call_RT(oop_result1, metadata_result, entry, 2); +} + + +int StubAssembler::call_RT(Register oop_result1, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3) { + mr_if_needed(R4_ARG2, arg1); + mr_if_needed(R5_ARG3, arg2); assert(arg2 != R4_ARG2, "smashed argument"); + mr_if_needed(R6_ARG4, arg3); assert(arg3 != R4_ARG2 && arg3 != R5_ARG3, "smashed argument"); + return call_RT(oop_result1, metadata_result, entry, 3); +} + + +// Implementation of Runtime1 + +#define __ sasm-> + +static int cpu_reg_save_offsets[FrameMap::nof_cpu_regs]; +static int fpu_reg_save_offsets[FrameMap::nof_fpu_regs]; +static int frame_size_in_bytes = -1; + +static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) { + assert(frame_size_in_bytes > frame::abi_reg_args_size, "init"); + sasm->set_frame_size(frame_size_in_bytes / BytesPerWord); + int frame_size_in_slots = frame_size_in_bytes / sizeof(jint); + OopMap* oop_map = new OopMap(frame_size_in_slots, 0); + + int i; + for (i = 0; i < FrameMap::nof_cpu_regs; i++) { + Register r = as_Register(i); + if (FrameMap::reg_needs_save(r)) { + int sp_offset = cpu_reg_save_offsets[i]; + oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset>>2), r->as_VMReg()); + oop_map->set_callee_saved(VMRegImpl::stack2reg((sp_offset>>2) + 1), r->as_VMReg()->next()); + } + } + + if (save_fpu_registers) { + for (i = 0; i < FrameMap::nof_fpu_regs; i++) { + FloatRegister r = as_FloatRegister(i); + int sp_offset = fpu_reg_save_offsets[i]; + oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset>>2), r->as_VMReg()); + oop_map->set_callee_saved(VMRegImpl::stack2reg((sp_offset>>2) + 1), r->as_VMReg()->next()); + } + } + + return oop_map; +} + +static OopMap* save_live_registers(StubAssembler* sasm, bool save_fpu_registers = true, + Register ret_pc = noreg, int stack_preserve = 0) { + if (ret_pc == noreg) { + ret_pc = R0; + __ mflr(ret_pc); + } + __ std(ret_pc, _abi(lr), R1_SP); // C code needs pc in C1 method. + __ push_frame(frame_size_in_bytes + stack_preserve, R0); + + // Record volatile registers as callee-save values in an OopMap so + // their save locations will be propagated to the caller frame's + // RegisterMap during StackFrameStream construction (needed for + // deoptimization; see compiledVFrame::create_stack_value). + // OopMap frame sizes are in c2 stack slot sizes (sizeof(jint)). + + int i; + for (i = 0; i < FrameMap::nof_cpu_regs; i++) { + Register r = as_Register(i); + if (FrameMap::reg_needs_save(r)) { + int sp_offset = cpu_reg_save_offsets[i]; + __ std(r, sp_offset + STACK_BIAS, R1_SP); + } + } + + if (save_fpu_registers) { + for (i = 0; i < FrameMap::nof_fpu_regs; i++) { + FloatRegister r = as_FloatRegister(i); + int sp_offset = fpu_reg_save_offsets[i]; + __ stfd(r, sp_offset + STACK_BIAS, R1_SP); + } + } + + return generate_oop_map(sasm, save_fpu_registers); +} + +static void restore_live_registers(StubAssembler* sasm, Register result1, Register result2, + bool restore_fpu_registers = true) { + for (int i = 0; i < FrameMap::nof_cpu_regs; i++) { + Register r = as_Register(i); + if (FrameMap::reg_needs_save(r) && r != result1 && r != result2) { + int sp_offset = cpu_reg_save_offsets[i]; + __ ld(r, sp_offset + STACK_BIAS, R1_SP); + } + } + + if (restore_fpu_registers) { + for (int i = 0; i < FrameMap::nof_fpu_regs; i++) { + FloatRegister r = as_FloatRegister(i); + int sp_offset = fpu_reg_save_offsets[i]; + __ lfd(r, sp_offset + STACK_BIAS, R1_SP); + } + } + + __ pop_frame(); + __ ld(R0, _abi(lr), R1_SP); + __ mtlr(R0); +} + + +void Runtime1::initialize_pd() { + int i; + int sp_offset = frame::abi_reg_args_size; + + for (i = 0; i < FrameMap::nof_cpu_regs; i++) { + Register r = as_Register(i); + if (FrameMap::reg_needs_save(r)) { + cpu_reg_save_offsets[i] = sp_offset; + sp_offset += BytesPerWord; + } + } + + for (i = 0; i < FrameMap::nof_fpu_regs; i++) { + fpu_reg_save_offsets[i] = sp_offset; + sp_offset += BytesPerWord; + } + frame_size_in_bytes = align_size_up(sp_offset, frame::alignment_in_bytes); +} + + +OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) { + // Make a frame and preserve the caller's caller-save registers. + OopMap* oop_map = save_live_registers(sasm); + + int call_offset; + if (!has_argument) { + call_offset = __ call_RT(noreg, noreg, target); + } else { + call_offset = __ call_RT(noreg, noreg, target, R4_ARG2); + } + OopMapSet* oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + __ should_not_reach_here(); + return oop_maps; +} + +static OopMapSet* generate_exception_throw_with_stack_parms(StubAssembler* sasm, address target, + int stack_parms) { + // Make a frame and preserve the caller's caller-save registers. + const int parm_size_in_bytes = align_size_up(stack_parms << LogBytesPerWord, frame::alignment_in_bytes); + const int padding = parm_size_in_bytes - (stack_parms << LogBytesPerWord); + OopMap* oop_map = save_live_registers(sasm, true, noreg, parm_size_in_bytes); + + int call_offset = 0; + switch (stack_parms) { + case 3: + __ ld(R6_ARG4, frame_size_in_bytes + padding + 16, R1_SP); + case 2: + __ ld(R5_ARG3, frame_size_in_bytes + padding + 8, R1_SP); + case 1: + __ ld(R4_ARG2, frame_size_in_bytes + padding + 0, R1_SP); + call_offset = __ call_RT(noreg, noreg, target); + break; + default: Unimplemented(); break; + } + OopMapSet* oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + __ should_not_reach_here(); + return oop_maps; +} + + +OopMapSet* Runtime1::generate_stub_call(StubAssembler* sasm, Register result, address target, + Register arg1, Register arg2, Register arg3) { + // Make a frame and preserve the caller's caller-save registers. + OopMap* oop_map = save_live_registers(sasm); + + int call_offset; + if (arg1 == noreg) { + call_offset = __ call_RT(result, noreg, target); + } else if (arg2 == noreg) { + call_offset = __ call_RT(result, noreg, target, arg1); + } else if (arg3 == noreg) { + call_offset = __ call_RT(result, noreg, target, arg1, arg2); + } else { + call_offset = __ call_RT(result, noreg, target, arg1, arg2, arg3); + } + OopMapSet* oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + restore_live_registers(sasm, result, noreg); + __ blr(); + return oop_maps; +} + +static OopMapSet* stub_call_with_stack_parms(StubAssembler* sasm, Register result, address target, + int stack_parms, bool do_return = true) { + // Make a frame and preserve the caller's caller-save registers. + const int parm_size_in_bytes = align_size_up(stack_parms << LogBytesPerWord, frame::alignment_in_bytes); + const int padding = parm_size_in_bytes - (stack_parms << LogBytesPerWord); + OopMap* oop_map = save_live_registers(sasm, true, noreg, parm_size_in_bytes); + + int call_offset = 0; + switch (stack_parms) { + case 3: + __ ld(R6_ARG4, frame_size_in_bytes + padding + 16, R1_SP); + case 2: + __ ld(R5_ARG3, frame_size_in_bytes + padding + 8, R1_SP); + case 1: + __ ld(R4_ARG2, frame_size_in_bytes + padding + 0, R1_SP); + call_offset = __ call_RT(result, noreg, target); + break; + default: Unimplemented(); break; + } + OopMapSet* oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + restore_live_registers(sasm, result, noreg); + if (do_return) __ blr(); + return oop_maps; +} + + +OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) { + // Make a frame and preserve the caller's caller-save registers. + OopMap* oop_map = save_live_registers(sasm); + + // Call the runtime patching routine, returns non-zero if nmethod got deopted. + int call_offset = __ call_RT(noreg, noreg, target); + OopMapSet* oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + __ cmpdi(CCR0, R3_RET, 0); + + // Re-execute the patched instruction or, if the nmethod was deoptmized, + // return to the deoptimization handler entry that will cause re-execution + // of the current bytecode. + DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); + assert(deopt_blob != NULL, "deoptimization blob must have been created"); + + // Return to the deoptimization handler entry for unpacking and rexecute. + // If we simply returned the we'd deopt as if any call we patched had just + // returned. + + restore_live_registers(sasm, noreg, noreg); + // Return if patching routine returned 0. + __ bclr(Assembler::bcondCRbiIs1, Assembler::bi0(CCR0, Assembler::equal), Assembler::bhintbhBCLRisReturn); + + address stub = deopt_blob->unpack_with_reexecution(); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + __ bctr(); + + return oop_maps; +} + +OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { + OopMapSet* oop_maps = NULL; + + // For better readability. + const bool must_gc_arguments = true; + const bool dont_gc_arguments = false; + + // Stub code & info for the different stubs. + switch (id) { + case forward_exception_id: + { + oop_maps = generate_handle_exception(id, sasm); + } + break; + + case new_instance_id: + case fast_new_instance_id: + case fast_new_instance_init_check_id: + { + if (id == new_instance_id) { + __ set_info("new_instance", dont_gc_arguments); + } else if (id == fast_new_instance_id) { + __ set_info("fast new_instance", dont_gc_arguments); + } else { + assert(id == fast_new_instance_init_check_id, "bad StubID"); + __ set_info("fast new_instance init check", dont_gc_arguments); + } + // We don't support eden allocation. +// if ((id == fast_new_instance_id || id == fast_new_instance_init_check_id) && +// UseTLAB && FastTLABRefill) { +// if (id == fast_new_instance_init_check_id) { +// // make sure the klass is initialized +// __ lbz(R0, in_bytes(InstanceKlass::init_state_offset()), R3_ARG1); +// __ cmpwi(CCR0, R0, InstanceKlass::fully_initialized); +// __ bne(CCR0, slow_path); +// } +//#ifdef ASSERT +// // assert object can be fast path allocated +// { +// Label ok, not_ok; +// __ lwz(R0, in_bytes(Klass::layout_helper_offset()), R3_ARG1); +// // make sure it's an instance (LH > 0) +// __ cmpwi(CCR0, R0, 0); +// __ ble(CCR0, not_ok); +// __ testbitdi(CCR0, R0, R0, Klass::_lh_instance_slow_path_bit); +// __ beq(CCR0, ok); +// +// __ bind(not_ok); +// __ stop("assert(can be fast path allocated)"); +// __ bind(ok); +// } +//#endif // ASSERT +// // We don't support eden allocation. +// __ bind(slow_path); +// } + oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_instance), R4_ARG2); + } + break; + + case counter_overflow_id: + // Bci and method are on stack. + oop_maps = stub_call_with_stack_parms(sasm, noreg, CAST_FROM_FN_PTR(address, counter_overflow), 2); + break; + + case new_type_array_id: + case new_object_array_id: + { + if (id == new_type_array_id) { + __ set_info("new_type_array", dont_gc_arguments); + } else { + __ set_info("new_object_array", dont_gc_arguments); + } + +#ifdef ASSERT + // Assert object type is really an array of the proper kind. + { + int tag = (id == new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_obj_value; + Label ok; + __ lwz(R0, in_bytes(Klass::layout_helper_offset()), R4_ARG2); + __ srawi(R0, R0, Klass::_lh_array_tag_shift); + __ cmpwi(CCR0, R0, tag); + __ beq(CCR0, ok); + __ stop("assert(is an array klass)"); + __ should_not_reach_here(); + __ bind(ok); + } +#endif // ASSERT + + // We don't support eden allocation. + + if (id == new_type_array_id) { + oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_type_array), R4_ARG2, R5_ARG3); + } else { + oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_object_array), R4_ARG2, R5_ARG3); + } + } + break; + + case new_multi_array_id: + { + // R4: klass + // R5: rank + // R6: address of 1st dimension + __ set_info("new_multi_array", dont_gc_arguments); + oop_maps = generate_stub_call(sasm, R3_RET, CAST_FROM_FN_PTR(address, new_multi_array), R4_ARG2, R5_ARG3, R6_ARG4); + } + break; + + case register_finalizer_id: + { + __ set_info("register_finalizer", dont_gc_arguments); + // This code is called via rt_call. Hence, caller-save registers have been saved. + Register t = R11_scratch1; + + // Load the klass and check the has finalizer flag. + __ load_klass(t, R3_ARG1); + __ lwz(t, in_bytes(Klass::access_flags_offset()), t); + __ testbitdi(CCR0, R0, t, exact_log2(JVM_ACC_HAS_FINALIZER)); + // Return if has_finalizer bit == 0 (CR0.eq). + __ bclr(Assembler::bcondCRbiIs1, Assembler::bi0(CCR0, Assembler::equal), Assembler::bhintbhBCLRisReturn); + + __ mflr(R0); + __ std(R0, _abi(lr), R1_SP); + __ push_frame(frame::abi_reg_args_size, R0); // Empty dummy frame (no callee-save regs). + sasm->set_frame_size(frame::abi_reg_args_size / BytesPerWord); + OopMap* oop_map = new OopMap(frame::abi_reg_args_size / sizeof(jint), 0); + int call_offset = __ call_RT(noreg, noreg, + CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer), R3_ARG1); + oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + __ pop_frame(); + __ ld(R0, _abi(lr), R1_SP); + __ mtlr(R0); + __ blr(); + } + break; + + case throw_range_check_failed_id: + { + __ set_info("range_check_failed", dont_gc_arguments); // Arguments will be discarded. + __ std(R0, -8, R1_SP); // Pass index on stack. + oop_maps = generate_exception_throw_with_stack_parms(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), 1); + } + break; + + case throw_index_exception_id: + { + __ set_info("index_range_check_failed", dont_gc_arguments); // Arguments will be discarded. + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true); + } + break; + + case throw_div0_exception_id: + { + __ set_info("throw_div0_exception", dont_gc_arguments); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false); + } + break; + + case throw_null_pointer_exception_id: + { + __ set_info("throw_null_pointer_exception", dont_gc_arguments); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false); + } + break; + + case handle_exception_nofpu_id: + case handle_exception_id: + { + __ set_info("handle_exception", dont_gc_arguments); + oop_maps = generate_handle_exception(id, sasm); + } + break; + + case handle_exception_from_callee_id: + { + __ set_info("handle_exception_from_callee", dont_gc_arguments); + oop_maps = generate_handle_exception(id, sasm); + } + break; + + case unwind_exception_id: + { + const Register Rexception = R3 /*LIRGenerator::exceptionOopOpr()*/, + Rexception_pc = R4 /*LIRGenerator::exceptionPcOpr()*/, + Rexception_save = R31, Rcaller_sp = R30; + __ set_info("unwind_exception", dont_gc_arguments); + + __ ld(Rcaller_sp, 0, R1_SP); + __ push_frame_reg_args(0, R0); // dummy frame for C call + __ mr(Rexception_save, Rexception); // save over C call + __ ld(Rexception_pc, _abi(lr), Rcaller_sp); // return pc + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), R16_thread, Rexception_pc); + __ verify_not_null_oop(Rexception_save); + __ mtctr(R3_RET); + __ ld(Rexception_pc, _abi(lr), Rcaller_sp); // return pc + __ mr(R1_SP, Rcaller_sp); // Pop both frames at once. + __ mr(Rexception, Rexception_save); // restore + __ mtlr(Rexception_pc); + __ bctr(); + } + break; + + case throw_array_store_exception_id: + { + __ set_info("throw_array_store_exception", dont_gc_arguments); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception), true); + } + break; + + case throw_class_cast_exception_id: + { + __ set_info("throw_class_cast_exception", dont_gc_arguments); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true); + } + break; + + case throw_incompatible_class_change_error_id: + { + __ set_info("throw_incompatible_class_cast_exception", dont_gc_arguments); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false); + } + break; + + case slow_subtype_check_id: + { // Support for uint StubRoutine::partial_subtype_check( Klass sub, Klass super ); + const Register sub_klass = R5, + super_klass = R4, + temp1_reg = R6, + temp2_reg = R0; + __ check_klass_subtype_slow_path(sub_klass, super_klass, temp1_reg, temp2_reg); // returns with CR0.eq if successful + __ crandc(CCR0, Assembler::equal, CCR0, Assembler::equal); // failed: CR0.ne + __ blr(); + } + break; + + case monitorenter_nofpu_id: + case monitorenter_id: + { + __ set_info("monitorenter", dont_gc_arguments); + + int save_fpu_registers = (id == monitorenter_id); + // Make a frame and preserve the caller's caller-save registers. + OopMap* oop_map = save_live_registers(sasm, save_fpu_registers); + + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter), R4_ARG2, R5_ARG3); + + oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + restore_live_registers(sasm, noreg, noreg, save_fpu_registers); + __ blr(); + } + break; + + case monitorexit_nofpu_id: + case monitorexit_id: + { + // note: Really a leaf routine but must setup last java sp + // => use call_RT for now (speed can be improved by + // doing last java sp setup manually). + __ set_info("monitorexit", dont_gc_arguments); + + int save_fpu_registers = (id == monitorexit_id); + // Make a frame and preserve the caller's caller-save registers. + OopMap* oop_map = save_live_registers(sasm, save_fpu_registers); + + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit), R4_ARG2); + + oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + restore_live_registers(sasm, noreg, noreg, save_fpu_registers); + __ blr(); + } + break; + + case deoptimize_id: + { + __ set_info("deoptimize", dont_gc_arguments); + __ std(R0, -8, R1_SP); // Pass trap_request on stack. + oop_maps = stub_call_with_stack_parms(sasm, noreg, CAST_FROM_FN_PTR(address, deoptimize), 1, /*do_return*/ false); + + DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); + assert(deopt_blob != NULL, "deoptimization blob must have been created"); + address stub = deopt_blob->unpack_with_reexecution(); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + __ bctr(); + } + break; + + case access_field_patching_id: + { + __ set_info("access_field_patching", dont_gc_arguments); + oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching)); + } + break; + + case load_klass_patching_id: + { + __ set_info("load_klass_patching", dont_gc_arguments); + oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching)); + } + break; + + case load_mirror_patching_id: + { + __ set_info("load_mirror_patching", dont_gc_arguments); + oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching)); + } + break; + + case load_appendix_patching_id: + { + __ set_info("load_appendix_patching", dont_gc_arguments); + oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching)); + } + break; + + case dtrace_object_alloc_id: + { // O0: object + __ unimplemented("stub dtrace_object_alloc_id"); + __ set_info("dtrace_object_alloc", dont_gc_arguments); +// // We can't gc here so skip the oopmap but make sure that all +// // the live registers get saved. +// save_live_registers(sasm); +// +// __ save_thread(L7_thread_cache); +// __ call(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), +// relocInfo::runtime_call_type); +// __ delayed()->mov(I0, O0); +// __ restore_thread(L7_thread_cache); +// +// restore_live_registers(sasm); +// __ ret(); +// __ delayed()->restore(); + } + break; + +#if INCLUDE_ALL_GCS + case g1_pre_barrier_slow_id: + { + BarrierSet* bs = Universe::heap()->barrier_set(); + if (bs->kind() != BarrierSet::G1SATBCTLogging) { + goto unimplemented_entry; + } + + __ set_info("g1_pre_barrier_slow_id", dont_gc_arguments); + + // Using stack slots: pre_val (pre-pushed), spill tmp, spill tmp2. + const int stack_slots = 3; + Register pre_val = R0; // previous value of memory + Register tmp = R14; + Register tmp2 = R15; + + Label refill, restart; + int satb_q_index_byte_offset = + in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_index()); + int satb_q_buf_byte_offset = + in_bytes(JavaThread::satb_mark_queue_offset() + + SATBMarkQueue::byte_offset_of_buf()); + + // Spill + __ std(tmp, -16, R1_SP); + __ std(tmp2, -24, R1_SP); + + __ bind(restart); + // Load the index into the SATB buffer. SATBMarkQueue::_index is a + // size_t so ld_ptr is appropriate. + __ ld(tmp, satb_q_index_byte_offset, R16_thread); + + // index == 0? + __ cmpdi(CCR0, tmp, 0); + __ beq(CCR0, refill); + + __ ld(tmp2, satb_q_buf_byte_offset, R16_thread); + __ ld(pre_val, -8, R1_SP); // Load from stack. + __ addi(tmp, tmp, -oopSize); + + __ std(tmp, satb_q_index_byte_offset, R16_thread); + __ stdx(pre_val, tmp2, tmp); // [_buf + index] := + + // Restore temp registers and return-from-leaf. + __ ld(tmp2, -24, R1_SP); + __ ld(tmp, -16, R1_SP); + __ blr(); + + __ bind(refill); + const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord; + __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ mflr(R0); + __ std(R0, _abi(lr), R1_SP); + __ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SATBMarkQueueSet::handle_zero_index_for_thread), R16_thread); + __ pop_frame(); + __ ld(R0, _abi(lr), R1_SP); + __ mtlr(R0); + __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ b(restart); + } + break; + + case g1_post_barrier_slow_id: + { + BarrierSet* bs = Universe::heap()->barrier_set(); + if (bs->kind() != BarrierSet::G1SATBCTLogging) { + goto unimplemented_entry; + } + + __ set_info("g1_post_barrier_slow_id", dont_gc_arguments); + + // Using stack slots: spill addr, spill tmp2 + const int stack_slots = 2; + Register tmp = R0; + Register addr = R14; + Register tmp2 = R15; + jbyte* byte_map_base = ((CardTableModRefBS*)bs)->byte_map_base; + + Label restart, refill, ret; + + // Spill + __ std(addr, -8, R1_SP); + __ std(tmp2, -16, R1_SP); + + __ srdi(addr, R0, CardTableModRefBS::card_shift); // Addr is passed in R0. + __ load_const_optimized(/*cardtable*/ tmp2, byte_map_base, tmp); + __ add(addr, tmp2, addr); + __ lbz(tmp, 0, addr); // tmp := [addr + cardtable] + + // Return if young card. + __ cmpwi(CCR0, tmp, G1SATBCardTableModRefBS::g1_young_card_val()); + __ beq(CCR0, ret); + + // Return if sequential consistent value is already dirty. + __ membar(Assembler::StoreLoad); + __ lbz(tmp, 0, addr); // tmp := [addr + cardtable] + + __ cmpwi(CCR0, tmp, G1SATBCardTableModRefBS::dirty_card_val()); + __ beq(CCR0, ret); + + // Not dirty. + + // First, dirty it. + __ li(tmp, G1SATBCardTableModRefBS::dirty_card_val()); + __ stb(tmp, 0, addr); + + int dirty_card_q_index_byte_offset = + in_bytes(JavaThread::dirty_card_queue_offset() + + DirtyCardQueue::byte_offset_of_index()); + int dirty_card_q_buf_byte_offset = + in_bytes(JavaThread::dirty_card_queue_offset() + + DirtyCardQueue::byte_offset_of_buf()); + + __ bind(restart); + + // Get the index into the update buffer. DirtyCardQueue::_index is + // a size_t so ld_ptr is appropriate here. + __ ld(tmp2, dirty_card_q_index_byte_offset, R16_thread); + + // index == 0? + __ cmpdi(CCR0, tmp2, 0); + __ beq(CCR0, refill); + + __ ld(tmp, dirty_card_q_buf_byte_offset, R16_thread); + __ addi(tmp2, tmp2, -oopSize); + + __ std(tmp2, dirty_card_q_index_byte_offset, R16_thread); + __ add(tmp2, tmp, tmp2); + __ std(addr, 0, tmp2); // [_buf + index] := + + // Restore temp registers and return-from-leaf. + __ bind(ret); + __ ld(tmp2, -16, R1_SP); + __ ld(addr, -8, R1_SP); + __ blr(); + + __ bind(refill); + const int nbytes_save = (MacroAssembler::num_volatile_regs + stack_slots) * BytesPerWord; + __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ mflr(R0); + __ std(R0, _abi(lr), R1_SP); + __ push_frame_reg_args(nbytes_save, R0); // dummy frame for C call + __ call_VM_leaf(CAST_FROM_FN_PTR(address, DirtyCardQueueSet::handle_zero_index_for_thread), R16_thread); + __ pop_frame(); + __ ld(R0, _abi(lr), R1_SP); + __ mtlr(R0); + __ restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 + __ b(restart); + } + break; +#endif // INCLUDE_ALL_GCS + + case predicate_failed_trap_id: + { + __ set_info("predicate_failed_trap", dont_gc_arguments); + OopMap* oop_map = save_live_registers(sasm); + + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, predicate_failed_trap)); + + oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + + DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); + assert(deopt_blob != NULL, "deoptimization blob must have been created"); + restore_live_registers(sasm, noreg, noreg); + + address stub = deopt_blob->unpack_with_reexecution(); + //__ load_const_optimized(R0, stub); + __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + __ mtctr(R0); + __ bctr(); + } + break; + + default: + unimplemented_entry: + { + __ set_info("unimplemented entry", dont_gc_arguments); + __ mflr(R0); + __ std(R0, _abi(lr), R1_SP); + __ push_frame(frame::abi_reg_args_size, R0); // empty dummy frame + sasm->set_frame_size(frame::abi_reg_args_size / BytesPerWord); + OopMap* oop_map = new OopMap(frame::abi_reg_args_size / sizeof(jint), 0); + + __ load_const_optimized(R4_ARG2, (int)id); + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R4_ARG2); + + oop_maps = new OopMapSet(); + oop_maps->add_gc_map(call_offset, oop_map); + __ should_not_reach_here(); + } + break; + } + return oop_maps; +} + + +OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler* sasm) { + __ block_comment("generate_handle_exception"); + + // Save registers, if required. + OopMapSet* oop_maps = new OopMapSet(); + OopMap* oop_map = NULL; + const Register Rexception = R3 /*LIRGenerator::exceptionOopOpr()*/, + Rexception_pc = R4 /*LIRGenerator::exceptionPcOpr()*/; + + switch (id) { + case forward_exception_id: + // We're handling an exception in the context of a compiled frame. + // The registers have been saved in the standard places. Perform + // an exception lookup in the caller and dispatch to the handler + // if found. Otherwise unwind and dispatch to the callers + // exception handler. + oop_map = generate_oop_map(sasm, true); + // Transfer the pending exception to the exception_oop. + // Also load the PC which is typically at SP + frame_size_in_bytes + _abi(lr), + // but we support additional slots in the frame for parameter passing. + __ ld(Rexception_pc, 0, R1_SP); + __ ld(Rexception, in_bytes(JavaThread::pending_exception_offset()), R16_thread); + __ li(R0, 0); + __ ld(Rexception_pc, _abi(lr), Rexception_pc); + __ std(R0, in_bytes(JavaThread::pending_exception_offset()), R16_thread); + break; + case handle_exception_nofpu_id: + case handle_exception_id: + // At this point all registers MAY be live. + oop_map = save_live_registers(sasm, id != handle_exception_nofpu_id, Rexception_pc); + break; + case handle_exception_from_callee_id: + // At this point all registers except exception oop and exception pc are dead. + oop_map = new OopMap(frame_size_in_bytes / sizeof(jint), 0); + sasm->set_frame_size(frame_size_in_bytes / BytesPerWord); + __ std(Rexception_pc, _abi(lr), R1_SP); + __ push_frame(frame_size_in_bytes, R0); + break; + default: ShouldNotReachHere(); + } + + __ verify_not_null_oop(Rexception); + +#ifdef ASSERT + // Check that fields in JavaThread for exception oop and issuing pc are + // empty before writing to them. + __ ld(R0, in_bytes(JavaThread::exception_oop_offset()), R16_thread); + __ cmpdi(CCR0, R0, 0); + __ asm_assert_eq("exception oop already set", 0x963); + __ ld(R0, in_bytes(JavaThread::exception_pc_offset() ), R16_thread); + __ cmpdi(CCR0, R0, 0); + __ asm_assert_eq("exception pc already set", 0x962); +#endif + + // Save the exception and issuing pc in the thread. + __ std(Rexception, in_bytes(JavaThread::exception_oop_offset()), R16_thread); + __ std(Rexception_pc, in_bytes(JavaThread::exception_pc_offset() ), R16_thread); + + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc)); + oop_maps->add_gc_map(call_offset, oop_map); + + __ mtctr(R3_RET); + + // Note: if nmethod has been deoptimized then regardless of + // whether it had a handler or not we will deoptimize + // by entering the deopt blob with a pending exception. + + // Restore the registers that were saved at the beginning, remove + // the frame and jump to the exception handler. + switch (id) { + case forward_exception_id: + case handle_exception_nofpu_id: + case handle_exception_id: + restore_live_registers(sasm, noreg, noreg, id != handle_exception_nofpu_id); + __ bctr(); + break; + case handle_exception_from_callee_id: { + __ pop_frame(); + __ ld(Rexception_pc, _abi(lr), R1_SP); + __ mtlr(Rexception_pc); + __ bctr(); + break; + } + default: ShouldNotReachHere(); + } + + return oop_maps; +} + +const char *Runtime1::pd_name_for_address(address entry) { + return ""; +} + +#undef __ diff --git a/hotspot/src/cpu/ppc/vm/c1_globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/c1_globals_ppc.hpp new file mode 100644 index 00000000000..234248e387e --- /dev/null +++ b/hotspot/src/cpu/ppc/vm/c1_globals_ppc.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 CPU_PPC_VM_C1_GLOBALS_PPC_HPP +#define CPU_PPC_VM_C1_GLOBALS_PPC_HPP + +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +// Sets the default values for platform dependent flags used by the client compiler. +// (see c1_globals.hpp) + +#ifndef TIERED +define_pd_global(bool, BackgroundCompilation, true ); +define_pd_global(bool, CICompileOSR, true ); +define_pd_global(bool, InlineIntrinsics, true ); +define_pd_global(bool, PreferInterpreterNativeStubs, false); +define_pd_global(bool, ProfileTraps, false); +define_pd_global(bool, UseOnStackReplacement, true ); +define_pd_global(bool, TieredCompilation, false); +define_pd_global(intx, CompileThreshold, 1000 ); + +define_pd_global(intx, OnStackReplacePercentage, 1400 ); +define_pd_global(bool, UseTLAB, true ); +define_pd_global(bool, ProfileInterpreter, false); +define_pd_global(intx, FreqInlineSize, 325 ); +define_pd_global(bool, ResizeTLAB, true ); +define_pd_global(intx, ReservedCodeCacheSize, 32*M ); +define_pd_global(intx, CodeCacheExpansionSize, 32*K ); +define_pd_global(uintx,CodeCacheMinBlockLength, 1); +define_pd_global(uintx,MetaspaceSize, 12*M ); +define_pd_global(bool, NeverActAsServerClassMachine, true ); +define_pd_global(intx, NewSizeThreadIncrease, 16*K ); +define_pd_global(uint64_t,MaxRAM, 1ULL*G); +define_pd_global(intx, InitialCodeCacheSize, 160*K); +#endif // !TIERED + +define_pd_global(bool, UseTypeProfile, false); +define_pd_global(bool, RoundFPResults, false); + +define_pd_global(bool, LIRFillDelaySlots, false); +define_pd_global(bool, OptimizeSinglePrecision, false); +define_pd_global(bool, CSEArrayLength, true ); +define_pd_global(bool, TwoOperandLIRForm, false); + +#endif // CPU_PPC_VM_C1_GLOBALS_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp index 20174522381..9934d1f0143 100644 --- a/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/c2_globals_ppc.hpp @@ -39,7 +39,7 @@ define_pd_global(bool, PreferInterpreterNativeStubs, false); define_pd_global(bool, ProfileTraps, true); define_pd_global(bool, UseOnStackReplacement, true); define_pd_global(bool, ProfileInterpreter, true); -define_pd_global(bool, TieredCompilation, false); +define_pd_global(bool, TieredCompilation, true); define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, OnStackReplacePercentage, 140); diff --git a/hotspot/src/cpu/ppc/vm/c2_init_ppc.cpp b/hotspot/src/cpu/ppc/vm/c2_init_ppc.cpp index 94b59db4d7e..9bfe48dd887 100644 --- a/hotspot/src/cpu/ppc/vm/c2_init_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/c2_init_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * 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,4 +45,8 @@ void Compile::pd_compiler2_init() { FLAG_SET_ERGO(bool, InsertEndGroupPPC64, true); } } + + if (!VM_Version::has_isel() && FLAG_IS_DEFAULT(ConditionalMoveLimit)) { + FLAG_SET_ERGO(intx, ConditionalMoveLimit, 0); + } } diff --git a/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp b/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp index 41b5125f06e..197d3069817 100644 --- a/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/compiledIC_ppc.cpp @@ -1,5 +1,6 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,13 +130,20 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* // - call __ calculate_address_from_global_toc(reg_scratch, __ method_toc()); AddressLiteral ic = __ allocate_metadata_address((Metadata *)NULL); - __ load_const_from_method_toc(as_Register(Matcher::inline_cache_reg_encode()), ic, reg_scratch); + bool success = __ load_const_from_method_toc(as_Register(Matcher::inline_cache_reg_encode()), + ic, reg_scratch, /*fixed_size*/ true); + if (!success) { + return NULL; // CodeCache is full + } if (ReoptimizeCallSequences) { __ b64_patchable((address)-1, relocInfo::none); } else { AddressLiteral a((address)-1); - __ load_const_from_method_toc(reg_scratch, a, reg_scratch); + success = __ load_const_from_method_toc(reg_scratch, a, reg_scratch, /*fixed_size*/ true); + if (!success) { + return NULL; // CodeCache is full + } __ mtctr(reg_scratch); __ bctr(); } @@ -153,6 +161,7 @@ address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark/* return stub; #else ShouldNotReachHere(); + return NULL; #endif } #undef __ diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp index 2e051d99918..304cddca9e6 100644 --- a/hotspot/src/cpu/ppc/vm/frame_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -271,39 +271,6 @@ void frame::describe_pd(FrameValues& values, int frame_no) { } #endif -void frame::adjust_unextended_sp() { - // If we are returning to a compiled MethodHandle call site, the - // saved_fp will in fact be a saved value of the unextended SP. The - // simplest way to tell whether we are returning to such a call site - // is as follows: - - if (is_compiled_frame() && false /*is_at_mh_callsite()*/) { // TODO PPC port - // If the sender PC is a deoptimization point, get the original - // PC. For MethodHandle call site the unextended_sp is stored in - // saved_fp. - _unextended_sp = _fp - _cb->frame_size(); - -#ifdef ASSERT - nmethod *sender_nm = _cb->as_nmethod_or_null(); - assert(sender_nm && *_sp == *_unextended_sp, "backlink changed"); - - intptr_t* sp = _unextended_sp; // check if stack can be walked from here - for (int x = 0; x < 5; ++x) { // check up to a couple of backlinks - intptr_t* prev_sp = *(intptr_t**)sp; - if (prev_sp == 0) break; // end of stack - assert(prev_sp>sp, "broken stack"); - sp = prev_sp; - } - - if (sender_nm->is_deopt_mh_entry(_pc)) { // checks for deoptimization - address original_pc = sender_nm->get_original_pc(this); - assert(sender_nm->insts_contains(original_pc), "original PC must be in nmethod"); - assert(sender_nm->is_method_handle_return(original_pc), "must be"); - } -#endif - } -} - intptr_t *frame::initial_deoptimization_info() { // unused... but returns fp() to minimize changes introduced by 7087445 return fp(); diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.hpp b/hotspot/src/cpu/ppc/vm/frame_ppc.hpp index f327d2ce424..c645307a945 100644 --- a/hotspot/src/cpu/ppc/vm/frame_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -465,7 +465,6 @@ // The frame's stack pointer before it has been extended by a c2i adapter; // needed by deoptimization intptr_t* _unextended_sp; - void adjust_unextended_sp(); public: diff --git a/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp index 4945d7f827b..fbd696cd47c 100644 --- a/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/frame_ppc.inline.hpp @@ -39,9 +39,6 @@ inline void frame::find_codeblob_and_set_pc_and_deopt_state(address pc) { _pc = pc; // Must be set for get_deopt_original_pc() _fp = (intptr_t*)own_abi()->callers_sp; - // Use _fp - frame_size, needs to be done between _cb and _pc initialization - // and get_deopt_original_pc. - adjust_unextended_sp(); address original_pc = nmethod::get_deopt_original_pc(this); if (original_pc != NULL) { diff --git a/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp b/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp index da5c8b008c5..542abd1bdb6 100644 --- a/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp @@ -36,4 +36,7 @@ const int StackAlignmentInBytes = 16; // The PPC CPUs are NOT multiple-copy-atomic. #define CPU_NOT_MULTIPLE_COPY_ATOMIC +// The expected size in bytes of a cache line, used to pad data structures. +#define DEFAULT_CACHE_LINE_SIZE 128 + #endif // CPU_PPC_VM_GLOBALDEFINITIONS_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp index be9c8da7124..a839ba4cb49 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.cpp @@ -93,9 +93,9 @@ void InterpreterMacroAssembler::dispatch_prolog(TosState state, int bcp_incr) { // own dispatch. The dispatch address in R24_dispatch_addr is used for the // dispatch. void InterpreterMacroAssembler::dispatch_epilog(TosState state, int bcp_incr) { + if (bcp_incr) { addi(R14_bcp, R14_bcp, bcp_incr); } mtctr(R24_dispatch_addr); - addi(R14_bcp, R14_bcp, bcp_incr); - bctr(); + bcctr(bcondAlways, 0, bhintbhBCCTRisNotPredictable); } void InterpreterMacroAssembler::check_and_handle_popframe(Register scratch_reg) { @@ -212,9 +212,6 @@ void InterpreterMacroAssembler::dispatch_Lbyte_code(TosState state, Register byt unimplemented("dispatch_Lbyte_code: verify"); // See Sparc Implementation to implement this } -#ifdef FAST_DISPATCH - unimplemented("dispatch_Lbyte_code FAST_DISPATCH"); -#else assert_different_registers(bytecode, R11_scratch1); // Calc dispatch table address. @@ -225,8 +222,7 @@ void InterpreterMacroAssembler::dispatch_Lbyte_code(TosState state, Register byt // Jump off! mtctr(R11_scratch1); - bctr(); -#endif + bcctr(bcondAlways, 0, bhintbhBCCTRisNotPredictable); } void InterpreterMacroAssembler::load_receiver(Register Rparam_count, Register Rrecv_dst) { @@ -546,8 +542,8 @@ void InterpreterMacroAssembler::index_check_without_pop(Register Rarray, Registe sldi(RsxtIndex, RsxtIndex, index_shift); blt(CCR0, LnotOOR); // Index should be in R17_tos, array should be in R4_ARG2. - mr(R17_tos, Rindex); - mr(R4_ARG2, Rarray); + mr_if_needed(R17_tos, Rindex); + mr_if_needed(R4_ARG2, Rarray); load_dispatch_table(Rtmp, (address*)Interpreter::_throw_ArrayIndexOutOfBoundsException_entry); mtctr(Rtmp); bctr(); @@ -842,7 +838,6 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // Must fence, otherwise, preceding store(s) may float below cmpxchg. // CmpxchgX sets CCR0 to cmpX(current, displaced). - fence(); // TODO: replace by MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq ? cmpxchgd(/*flag=*/CCR0, /*current_value=*/current_header, /*compare_value=*/displaced_header, /*exchange_value=*/monitor, @@ -850,7 +845,8 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, MacroAssembler::cmpxchgx_hint_acquire_lock(), noreg, - &cas_failed); + &cas_failed, + /*check without membar and ldarx first*/true); // If the compare-and-exchange succeeded, then we found an unlocked // object and we have now locked it. @@ -868,9 +864,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { sub(current_header, current_header, R1_SP); assert(os::vm_page_size() > 0xfff, "page size too small - change the constant"); - load_const_optimized(tmp, - (address) (~(os::vm_page_size()-1) | - markOopDesc::lock_mask_in_place)); + load_const_optimized(tmp, ~(os::vm_page_size()-1) | markOopDesc::lock_mask_in_place); and_(R0/*==0?*/, current_header, tmp); // If condition is true we are done and hence we can store 0 in the displaced @@ -1107,6 +1101,7 @@ void InterpreterMacroAssembler::verify_method_data_pointer() { } void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocation_count, + Register method_counters, Register Rscratch, Label &profile_continue) { assert(ProfileInterpreter, "must be profiling interpreter"); @@ -1115,12 +1110,11 @@ void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocat Label done; // If no method data exists, and the counter is high enough, make one. - int ipl_offs = load_const_optimized(Rscratch, &InvocationCounter::InterpreterProfileLimit, R0, true); - lwz(Rscratch, ipl_offs, Rscratch); + lwz(Rscratch, in_bytes(MethodCounters::interpreter_profile_limit_offset()), method_counters); cmpdi(CCR0, R28_mdx, 0); // Test to see if we should create a method data oop. - cmpd(CCR1, Rscratch /* InterpreterProfileLimit */, invocation_count); + cmpd(CCR1, Rscratch, invocation_count); bne(CCR0, done); bge(CCR1, profile_continue); @@ -1133,15 +1127,15 @@ void InterpreterMacroAssembler::test_invocation_counter_for_mdp(Register invocat bind(done); } -void InterpreterMacroAssembler::test_backedge_count_for_osr(Register backedge_count, Register branch_bcp, Register Rtmp) { - assert_different_registers(backedge_count, Rtmp, branch_bcp); +void InterpreterMacroAssembler::test_backedge_count_for_osr(Register backedge_count, Register method_counters, + Register target_bcp, Register disp, Register Rtmp) { + assert_different_registers(backedge_count, target_bcp, disp, Rtmp, R4_ARG2); assert(UseOnStackReplacement,"Must UseOnStackReplacement to test_backedge_count_for_osr"); Label did_not_overflow; Label overflow_with_error; - int ibbl_offs = load_const_optimized(Rtmp, &InvocationCounter::InterpreterBackwardBranchLimit, R0, true); - lwz(Rtmp, ibbl_offs, Rtmp); + lwz(Rtmp, in_bytes(MethodCounters::interpreter_backward_branch_limit_offset()), method_counters); cmpw(CCR0, backedge_count, Rtmp); blt(CCR0, did_not_overflow); @@ -1153,17 +1147,15 @@ void InterpreterMacroAssembler::test_backedge_count_for_osr(Register backedge_co // the overflow function is called only once every overflow_frequency. if (ProfileInterpreter) { const int overflow_frequency = 1024; - li(Rtmp, overflow_frequency-1); - andr(Rtmp, Rtmp, backedge_count); - cmpwi(CCR0, Rtmp, 0); + andi_(Rtmp, backedge_count, overflow_frequency-1); bne(CCR0, did_not_overflow); } // Overflow in loop, pass branch bytecode. - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), branch_bcp, true); + subf(R4_ARG2, disp, target_bcp); // Compute branch bytecode (previous bcp). + call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R4_ARG2, true); // Was an OSR adapter generated? - // O0 = osr nmethod cmpdi(CCR0, R3_RET, 0); beq(CCR0, overflow_with_error); @@ -1324,7 +1316,7 @@ void InterpreterMacroAssembler::increment_backedge_counter(const Register Rcount assert_different_registers(Rdst, Rtmp1); const Register invocation_counter = Rtmp1; const Register counter = Rdst; - // TODO ppc port assert(4 == InvocationCounter::sz_counter(), "unexpected field size."); + // TODO: PPC port: assert(4 == InvocationCounter::sz_counter(), "unexpected field size."); // Load backedge counter. lwz(counter, in_bytes(MethodCounters::backedge_counter_offset()) + @@ -1337,8 +1329,7 @@ void InterpreterMacroAssembler::increment_backedge_counter(const Register Rcount addi(counter, counter, InvocationCounter::count_increment); // Mask the invocation counter. - li(Rscratch, InvocationCounter::count_mask_value); - andr(invocation_counter, invocation_counter, Rscratch); + andi(invocation_counter, invocation_counter, InvocationCounter::count_mask_value); // Store new counter value. stw(counter, in_bytes(MethodCounters::backedge_counter_offset()) + @@ -1817,15 +1808,13 @@ void InterpreterMacroAssembler::profile_return_type(Register ret, Register tmp1, test_method_data_pointer(profile_continue); if (MethodData::profile_return_jsr292_only()) { - assert(Method::intrinsic_id_size_in_bytes() == 2, "assuming Method::_intrinsic_id is u2"); - // If we don't profile all invoke bytecodes we must make sure // it's a bytecode we indeed profile. We can't go back to the // begining of the ProfileData we intend to update to check its // type because we're right after it and we don't known its // length. lbz(tmp1, 0, R14_bcp); - lhz(tmp2, Method::intrinsic_id_offset_in_bytes(), R19_method); + lbz(tmp2, Method::intrinsic_id_offset_in_bytes(), R19_method); cmpwi(CCR0, tmp1, Bytecodes::_invokedynamic); cmpwi(CCR1, tmp1, Bytecodes::_invokehandle); cror(CCR0, Assembler::equal, CCR1, Assembler::equal); @@ -2207,9 +2196,7 @@ void InterpreterMacroAssembler::increment_invocation_counter(Register Rcounters, // Load the backedge counter. lwz(backedge_count, be_counter_offset, Rcounters); // is unsigned int // Mask the backedge counter. - Register tmp = invocation_count; - li(tmp, InvocationCounter::count_mask_value); - andr(backedge_count, tmp, backedge_count); // Cannot use andi, need sign extension of count_mask_value. + andi(backedge_count, backedge_count, InvocationCounter::count_mask_value); // Load the invocation counter. lwz(invocation_count, inv_counter_offset, Rcounters); // is unsigned int @@ -2266,7 +2253,7 @@ void InterpreterMacroAssembler::verify_oop_or_return_address(Register reg, Regis bne(CCR0, test); address fd = CAST_FROM_FN_PTR(address, verify_return_address); - const int nbytes_save = 11*8; // volatile gprs except R0 + const int nbytes_save = MacroAssembler::num_volatile_regs * 8; save_volatile_gprs(R1_SP, -nbytes_save); // except R0 save_LR_CR(Rtmp); // Save in old frame. push_frame_reg_args(nbytes_save, Rtmp); diff --git a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp index 9692e65225c..5baf225c199 100644 --- a/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp +++ b/hotspot/src/cpu/ppc/vm/interp_masm_ppc_64.hpp @@ -203,7 +203,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void restore_interpreter_state(Register scratch, bool bcp_and_mdx_only = false); void increment_backedge_counter(const Register Rcounters, Register Rtmp, Register Rtmp2, Register Rscratch); - void test_backedge_count_for_osr(Register backedge_count, Register branch_bcp, Register Rtmp); + void test_backedge_count_for_osr(Register backedge_count, Register method_counters, Register target_bcp, Register disp, Register Rtmp); void record_static_call_in_profile(Register Rentry, Register Rtmp); void record_receiver_call_in_profile(Register Rklass, Register Rentry, Register Rtmp); @@ -222,7 +222,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void set_method_data_pointer_for_bcp(); void test_method_data_pointer(Label& zero_continue); void verify_method_data_pointer(); - void test_invocation_counter_for_mdp(Register invocation_count, Register Rscratch, Label &profile_continue); + void test_invocation_counter_for_mdp(Register invocation_count, Register method_counters, Register Rscratch, Label &profile_continue); void set_mdp_data_at(int constant, Register value); diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index 38cf28d094a..1ba560b3160 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -30,6 +30,7 @@ #include "gc/shared/collectedHeap.inline.hpp" #include "interpreter/interpreter.hpp" #include "memory/resourceArea.hpp" +#include "nativeInst_ppc.hpp" #include "prims/methodHandles.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/icache.hpp" @@ -114,7 +115,7 @@ void MacroAssembler::calculate_address_from_global_toc(Register dst, address add } if (hi16) { - addis(dst, R29, MacroAssembler::largeoffset_si16_si16_hi(offset)); + addis(dst, R29_TOC, MacroAssembler::largeoffset_si16_si16_hi(offset)); } if (lo16) { if (add_relocation) { @@ -256,7 +257,9 @@ narrowOop MacroAssembler::get_narrow_oop(address a, address bound) { } #endif // _LP64 -void MacroAssembler::load_const_from_method_toc(Register dst, AddressLiteral& a, Register toc) { +// Returns true if successful. +bool MacroAssembler::load_const_from_method_toc(Register dst, AddressLiteral& a, + Register toc, bool fixed_size) { int toc_offset = 0; // Use RelocationHolder::none for the constant pool entry, otherwise // we will end up with a failing NativeCall::verify(x) where x is @@ -264,11 +267,13 @@ void MacroAssembler::load_const_from_method_toc(Register dst, AddressLiteral& a, // FIXME: We should insert relocation information for oops at the constant // pool entries instead of inserting it at the loads; patching of a constant // pool entry should be less expensive. - address oop_address = address_constant((address)a.value(), RelocationHolder::none); + address const_address = address_constant((address)a.value(), RelocationHolder::none); + if (const_address == NULL) { return false; } // allocation failure // Relocate at the pc of the load. relocate(a.rspec()); - toc_offset = (int)(oop_address - code()->consts()->start()); - ld_largeoffset_unchecked(dst, toc_offset, toc, true); + toc_offset = (int)(const_address - code()->consts()->start()); + ld_largeoffset_unchecked(dst, toc_offset, toc, fixed_size); + return true; } bool MacroAssembler::is_load_const_from_method_toc_at(address a) { @@ -446,6 +451,15 @@ void MacroAssembler::bc_far(int boint, int biint, Label& dest, int optimize) { assert(dest.is_bound() || target_pc == b_pc, "postcondition"); } +// 1 or 2 instructions +void MacroAssembler::bc_far_optimized(int boint, int biint, Label& dest) { + if (dest.is_bound() && is_within_range_of_bcxx(target(dest), pc())) { + bc(boint, biint, dest); + } else { + bc_far(boint, biint, dest, MacroAssembler::bc_far_optimize_on_relocate); + } +} + bool MacroAssembler::is_bc_far_at(address instruction_addr) { return is_bc_far_variant1_at(instruction_addr) || is_bc_far_variant2_at(instruction_addr) || @@ -496,7 +510,7 @@ void MacroAssembler::set_dest_of_bc_far_at(address instruction_addr, address des // variant 1, the 1st instruction contains the destination address: // // bcxx DEST - // endgroup + // nop // const int instruction_1 = *(int*)(instruction_addr); boint = inv_bo_field(instruction_1); @@ -523,10 +537,10 @@ void MacroAssembler::set_dest_of_bc_far_at(address instruction_addr, address des // variant 1: // // bcxx DEST - // endgroup + // nop // masm.bc(boint, biint, dest); - masm.endgroup(); + masm.nop(); } else { // variant 2: // @@ -810,7 +824,22 @@ void MacroAssembler::save_volatile_gprs(Register dst, int offset) { std(R9, offset, dst); offset += 8; std(R10, offset, dst); offset += 8; std(R11, offset, dst); offset += 8; - std(R12, offset, dst); + std(R12, offset, dst); offset += 8; + + stfd(F0, offset, dst); offset += 8; + stfd(F1, offset, dst); offset += 8; + stfd(F2, offset, dst); offset += 8; + stfd(F3, offset, dst); offset += 8; + stfd(F4, offset, dst); offset += 8; + stfd(F5, offset, dst); offset += 8; + stfd(F6, offset, dst); offset += 8; + stfd(F7, offset, dst); offset += 8; + stfd(F8, offset, dst); offset += 8; + stfd(F9, offset, dst); offset += 8; + stfd(F10, offset, dst); offset += 8; + stfd(F11, offset, dst); offset += 8; + stfd(F12, offset, dst); offset += 8; + stfd(F13, offset, dst); } // For verify_oops. @@ -825,7 +854,22 @@ void MacroAssembler::restore_volatile_gprs(Register src, int offset) { ld(R9, offset, src); offset += 8; ld(R10, offset, src); offset += 8; ld(R11, offset, src); offset += 8; - ld(R12, offset, src); + ld(R12, offset, src); offset += 8; + + lfd(F0, offset, src); offset += 8; + lfd(F1, offset, src); offset += 8; + lfd(F2, offset, src); offset += 8; + lfd(F3, offset, src); offset += 8; + lfd(F4, offset, src); offset += 8; + lfd(F5, offset, src); offset += 8; + lfd(F6, offset, src); offset += 8; + lfd(F7, offset, src); offset += 8; + lfd(F8, offset, src); offset += 8; + lfd(F9, offset, src); offset += 8; + lfd(F10, offset, src); offset += 8; + lfd(F11, offset, src); offset += 8; + lfd(F12, offset, src); offset += 8; + lfd(F13, offset, src); } void MacroAssembler::save_LR_CR(Register tmp) { @@ -908,7 +952,7 @@ void MacroAssembler::push_frame(unsigned int bytes, Register tmp) { if (is_simm(-offset, 16)) { stdu(R1_SP, -offset, R1_SP); } else { - load_const(tmp, -offset); + load_const_optimized(tmp, -offset); stdux(R1_SP, R1_SP, tmp); } } @@ -1090,20 +1134,21 @@ address MacroAssembler::call_c_using_toc(const FunctionDescriptor* fd, assert(fd->entry() != NULL, "function must be linked"); AddressLiteral fd_entry(fd->entry()); - load_const_from_method_toc(R11, fd_entry, toc); + bool success = load_const_from_method_toc(R11, fd_entry, toc, /*fixed_size*/ true); mtctr(R11); if (fd->env() == NULL) { li(R11, 0); nop(); } else { AddressLiteral fd_env(fd->env()); - load_const_from_method_toc(R11, fd_env, toc); + success = success && load_const_from_method_toc(R11, fd_env, toc, /*fixed_size*/ true); } AddressLiteral fd_toc(fd->toc()); - load_toc_from_toc(R2_TOC, fd_toc, toc); - // R2_TOC is killed. + // Set R2_TOC (load from toc) + success = success && load_const_from_method_toc(R2_TOC, fd_toc, toc, /*fixed_size*/ true); bctrl(); _last_calls_return_pc = pc(); + if (!success) { return NULL; } } else { // It's a friend function, load the entry point and don't care about // toc and env. Use an optimizable call instruction, but ensure the @@ -1367,11 +1412,6 @@ void MacroAssembler::cmpxchgw(ConditionRegister flag, Register dest_current_valu bool preset_result_reg = (int_flag_success != dest_current_value && int_flag_success != compare_value && int_flag_success != exchange_value && int_flag_success != addr_base); - // release/fence semantics - if (semantics & MemBarRel) { - release(); - } - if (use_result_reg && preset_result_reg) { li(int_flag_success, 0); // preset (assume cas failed) } @@ -1383,6 +1423,11 @@ void MacroAssembler::cmpxchgw(ConditionRegister flag, Register dest_current_valu bne(flag, failed); } + // release/fence semantics + if (semantics & MemBarRel) { + release(); + } + // atomic emulation loop bind(retry); @@ -1462,11 +1507,6 @@ void MacroAssembler::cmpxchgd(ConditionRegister flag, int_flag_success!=exchange_value && int_flag_success!=addr_base); assert(int_flag_success == noreg || failed_ext == NULL, "cannot have both"); - // release/fence semantics - if (semantics & MemBarRel) { - release(); - } - if (use_result_reg && preset_result_reg) { li(int_flag_success, 0); // preset (assume cas failed) } @@ -1478,6 +1518,11 @@ void MacroAssembler::cmpxchgd(ConditionRegister flag, bne(flag, failed); } + // release/fence semantics + if (semantics & MemBarRel) { + release(); + } + // atomic emulation loop bind(retry); @@ -1501,8 +1546,6 @@ void MacroAssembler::cmpxchgd(ConditionRegister flag, li(int_flag_success, 1); } - // POWER6 doesn't need isync in CAS. - // Always emit isync to be on the safe side. if (semantics & MemBarFenceAfter) { fence(); } else if (semantics & MemBarAcq) { @@ -1627,13 +1670,14 @@ void MacroAssembler::lookup_virtual_method(Register recv_klass, } /////////////////////////////////////////// subtype checking //////////////////////////////////////////// - void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, Register super_klass, Register temp1_reg, Register temp2_reg, - Label& L_success, - Label& L_failure) { + Label* L_success, + Label* L_failure, + Label* L_slow_path, + RegisterOrConstant super_check_offset) { const Register check_cache_offset = temp1_reg; const Register cached_super = temp2_reg; @@ -1643,6 +1687,18 @@ void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, int sco_offset = in_bytes(Klass::super_check_offset_offset()); int sc_offset = in_bytes(Klass::secondary_super_cache_offset()); + bool must_load_sco = (super_check_offset.constant_or_zero() == -1); + bool need_slow_path = (must_load_sco || super_check_offset.constant_or_zero() == sco_offset); + + Label L_fallthrough; + int label_nulls = 0; + if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } + if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } + if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; } + assert(label_nulls <= 1 || + (L_slow_path == &L_fallthrough && label_nulls <= 2 && !need_slow_path), + "at most one NULL in the batch, usually"); + // If the pointers are equal, we are done (e.g., String[] elements). // This self-check enables sharing of secondary supertype arrays among // non-primary types such as array-of-interface. Otherwise, each such @@ -1651,15 +1707,20 @@ void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, // type checks are in fact trivially successful in this manner, // so we get a nicely predicted branch right at the start of the check. cmpd(CCR0, sub_klass, super_klass); - beq(CCR0, L_success); + beq(CCR0, *L_success); // Check the supertype display: + if (must_load_sco) { + // The super check offset is always positive... lwz(check_cache_offset, sco_offset, super_klass); + super_check_offset = RegisterOrConstant(check_cache_offset); + // super_check_offset is register. + assert_different_registers(sub_klass, super_klass, cached_super, super_check_offset.as_register()); + } // The loaded value is the offset from KlassOopDesc. - ldx(cached_super, check_cache_offset, sub_klass); + ld(cached_super, super_check_offset, sub_klass); cmpd(CCR0, cached_super, super_klass); - beq(CCR0, L_success); // This check has worked decisively for primary supers. // Secondary supers are sought in the super_cache ('super_cache_addr'). @@ -1672,9 +1733,39 @@ void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, // So if it was a primary super, we can just fail immediately. // Otherwise, it's the slow path for us (no success at this point). - cmpwi(CCR0, check_cache_offset, sc_offset); - bne(CCR0, L_failure); - // bind(slow_path); // fallthru +#define FINAL_JUMP(label) if (&(label) != &L_fallthrough) { b(label); } + + if (super_check_offset.is_register()) { + beq(CCR0, *L_success); + cmpwi(CCR0, super_check_offset.as_register(), sc_offset); + if (L_failure == &L_fallthrough) { + beq(CCR0, *L_slow_path); + } else { + bne(CCR0, *L_failure); + FINAL_JUMP(*L_slow_path); + } + } else { + if (super_check_offset.as_constant() == sc_offset) { + // Need a slow path; fast failure is impossible. + if (L_slow_path == &L_fallthrough) { + beq(CCR0, *L_success); + } else { + bne(CCR0, *L_slow_path); + FINAL_JUMP(*L_success); + } + } else { + // No slow path; it's a fast decision. + if (L_failure == &L_fallthrough) { + beq(CCR0, *L_success); + } else { + bne(CCR0, *L_failure); + FINAL_JUMP(*L_success); + } + } + } + + bind(L_fallthrough); +#undef FINAL_JUMP } void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, @@ -1698,7 +1789,7 @@ void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, ld(array_ptr, source_offset, sub_klass); - //assert(4 == arrayOopDesc::length_length_in_bytes(), "precondition violated."); + // TODO: PPC port: assert(4 == arrayOopDesc::length_length_in_bytes(), "precondition violated."); lwz(temp, length_offset, array_ptr); cmpwi(CCR0, temp, 0); beq(CCR0, result_reg!=noreg ? failure : fallthru); // length 0 @@ -1719,8 +1810,9 @@ void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, bind(hit); std(super_klass, target_offset, sub_klass); // save result to cache - if (result_reg != noreg) li(result_reg, 0); // load zero result (indicates a hit) - if (L_success != NULL) b(*L_success); + if (result_reg != noreg) { li(result_reg, 0); } // load zero result (indicates a hit) + if (L_success != NULL) { b(*L_success); } + else if (result_reg == noreg) { blr(); } // return with CR0.eq if neither label nor result reg provided bind(fallthru); } @@ -1732,7 +1824,7 @@ void MacroAssembler::check_klass_subtype(Register sub_klass, Register temp2_reg, Label& L_success) { Label L_failure; - check_klass_subtype_fast_path(sub_klass, super_klass, temp1_reg, temp2_reg, L_success, L_failure); + check_klass_subtype_fast_path(sub_klass, super_klass, temp1_reg, temp2_reg, &L_success, &L_failure); check_klass_subtype_slow_path(sub_klass, super_klass, temp1_reg, temp2_reg, &L_success); bind(L_failure); // Fallthru if not successful. } @@ -1765,6 +1857,7 @@ RegisterOrConstant MacroAssembler::argument_offset(RegisterOrConstant arg_slot, } } +// Supports temp2_reg = R0. void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj_reg, Register mark_reg, Register temp_reg, Register temp2_reg, Label& done, Label* slow_case) { @@ -1788,10 +1881,10 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj "biased locking makes assumptions about bit layout"); if (PrintBiasedLockingStatistics) { - load_const(temp_reg, (address) BiasedLocking::total_entry_count_addr(), temp2_reg); - lwz(temp2_reg, 0, temp_reg); - addi(temp2_reg, temp2_reg, 1); - stw(temp2_reg, 0, temp_reg); + load_const(temp2_reg, (address) BiasedLocking::total_entry_count_addr(), temp_reg); + lwzx(temp_reg, temp2_reg); + addi(temp_reg, temp_reg, 1); + stwx(temp_reg, temp2_reg); } andi(temp_reg, mark_reg, markOopDesc::biased_lock_mask_in_place); @@ -1809,10 +1902,10 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj if (PrintBiasedLockingStatistics) { Label l; bne(cr_reg, l); - load_const(mark_reg, (address) BiasedLocking::biased_lock_entry_count_addr()); - lwz(temp2_reg, 0, mark_reg); - addi(temp2_reg, temp2_reg, 1); - stw(temp2_reg, 0, mark_reg); + load_const(temp2_reg, (address) BiasedLocking::biased_lock_entry_count_addr()); + lwzx(mark_reg, temp2_reg); + addi(mark_reg, mark_reg, 1); + stwx(mark_reg, temp2_reg); // restore mark_reg ld(mark_reg, oopDesc::mark_offset_in_bytes(), obj_reg); bind(l); @@ -1878,10 +1971,10 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj // need to revoke that bias. The revocation will occur in the // interpreter runtime in the slow case. if (PrintBiasedLockingStatistics) { - load_const(temp_reg, (address) BiasedLocking::anonymously_biased_lock_entry_count_addr(), temp2_reg); - lwz(temp2_reg, 0, temp_reg); - addi(temp2_reg, temp2_reg, 1); - stw(temp2_reg, 0, temp_reg); + load_const(temp2_reg, (address) BiasedLocking::anonymously_biased_lock_entry_count_addr(), temp_reg); + lwzx(temp_reg, temp2_reg); + addi(temp_reg, temp_reg, 1); + stwx(temp_reg, temp2_reg); } b(done); @@ -1892,15 +1985,14 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj // value as the comparison value when doing the cas to acquire the // bias in the current epoch. In other words, we allow transfer of // the bias from one thread to another directly in this situation. - andi(temp_reg, mark_reg, markOopDesc::age_mask_in_place); - orr(temp_reg, R16_thread, temp_reg); - load_klass(temp2_reg, obj_reg); - ld(temp2_reg, in_bytes(Klass::prototype_header_offset()), temp2_reg); - orr(temp_reg, temp_reg, temp2_reg); + load_klass(temp_reg, obj_reg); + andi(temp2_reg, mark_reg, markOopDesc::age_mask_in_place); + orr(temp2_reg, R16_thread, temp2_reg); + ld(temp_reg, in_bytes(Klass::prototype_header_offset()), temp_reg); + orr(temp_reg, temp2_reg, temp_reg); assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); - // CmpxchgX sets cr_reg to cmpX(temp2_reg, mark_reg). cmpxchgd(/*flag=*/cr_reg, /*current_value=*/temp2_reg, /*compare_value=*/mark_reg, /*exchange_value=*/temp_reg, /*where=*/obj_reg, @@ -1913,10 +2005,10 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj // need to revoke that bias. The revocation will occur in the // interpreter runtime in the slow case. if (PrintBiasedLockingStatistics) { - load_const(temp_reg, (address) BiasedLocking::rebiased_lock_entry_count_addr(), temp2_reg); - lwz(temp2_reg, 0, temp_reg); - addi(temp2_reg, temp2_reg, 1); - stw(temp2_reg, 0, temp_reg); + load_const(temp2_reg, (address) BiasedLocking::rebiased_lock_entry_count_addr(), temp_reg); + lwzx(temp_reg, temp2_reg); + addi(temp_reg, temp_reg, 1); + stwx(temp_reg, temp2_reg); } b(done); @@ -1952,10 +2044,10 @@ void MacroAssembler::biased_locking_enter(ConditionRegister cr_reg, Register obj if (PrintBiasedLockingStatistics) { Label l; bne(cr_reg, l); - load_const(temp_reg, (address) BiasedLocking::revoked_lock_entry_count_addr(), temp2_reg); - lwz(temp2_reg, 0, temp_reg); - addi(temp2_reg, temp2_reg, 1); - stw(temp2_reg, 0, temp_reg); + load_const(temp2_reg, (address) BiasedLocking::revoked_lock_entry_count_addr(), temp_reg); + lwzx(temp_reg, temp2_reg); + addi(temp_reg, temp_reg, 1); + stwx(temp_reg, temp2_reg); bind(l); } @@ -1977,6 +2069,109 @@ void MacroAssembler::biased_locking_exit (ConditionRegister cr_reg, Register mar beq(cr_reg, done); } +// allocation (for C1) +void MacroAssembler::eden_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Register t2, // temp register + Label& slow_case // continuation point if fast allocation fails +) { + b(slow_case); +} + +void MacroAssembler::tlab_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Label& slow_case // continuation point if fast allocation fails +) { + // make sure arguments make sense + assert_different_registers(obj, var_size_in_bytes, t1); + assert(0 <= con_size_in_bytes && is_simm13(con_size_in_bytes), "illegal object size"); + assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment"); + + const Register new_top = t1; + //verify_tlab(); not implemented + + ld(obj, in_bytes(JavaThread::tlab_top_offset()), R16_thread); + ld(R0, in_bytes(JavaThread::tlab_end_offset()), R16_thread); + if (var_size_in_bytes == noreg) { + addi(new_top, obj, con_size_in_bytes); + } else { + add(new_top, obj, var_size_in_bytes); + } + cmpld(CCR0, new_top, R0); + bc_far_optimized(Assembler::bcondCRbiIs1, bi0(CCR0, Assembler::greater), slow_case); + +#ifdef ASSERT + // make sure new free pointer is properly aligned + { + Label L; + andi_(R0, new_top, MinObjAlignmentInBytesMask); + beq(CCR0, L); + stop("updated TLAB free is not properly aligned", 0x934); + bind(L); + } +#endif // ASSERT + + // update the tlab top pointer + std(new_top, in_bytes(JavaThread::tlab_top_offset()), R16_thread); + //verify_tlab(); not implemented +} +void MacroAssembler::tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case) { + unimplemented("tlab_refill"); +} +void MacroAssembler::incr_allocated_bytes(RegisterOrConstant size_in_bytes, Register t1, Register t2) { + unimplemented("incr_allocated_bytes"); +} + +address MacroAssembler::emit_trampoline_stub(int destination_toc_offset, + int insts_call_instruction_offset, Register Rtoc) { + // Start the stub. + address stub = start_a_stub(64); + if (stub == NULL) { return NULL; } // CodeCache full: bail out + + // Create a trampoline stub relocation which relates this trampoline stub + // with the call instruction at insts_call_instruction_offset in the + // instructions code-section. + relocate(trampoline_stub_Relocation::spec(code()->insts()->start() + insts_call_instruction_offset)); + const int stub_start_offset = offset(); + + // For java_to_interp stubs we use R11_scratch1 as scratch register + // and in call trampoline stubs we use R12_scratch2. This way we + // can distinguish them (see is_NativeCallTrampolineStub_at()). + Register reg_scratch = R12_scratch2; + + // Now, create the trampoline stub's code: + // - load the TOC + // - load the call target from the constant pool + // - call + if (Rtoc == noreg) { + calculate_address_from_global_toc(reg_scratch, method_toc()); + Rtoc = reg_scratch; + } + + ld_largeoffset_unchecked(reg_scratch, destination_toc_offset, Rtoc, false); + mtctr(reg_scratch); + bctr(); + + const address stub_start_addr = addr_at(stub_start_offset); + + // Assert that the encoded destination_toc_offset can be identified and that it is correct. + assert(destination_toc_offset == NativeCallTrampolineStub_at(stub_start_addr)->destination_toc_offset(), + "encoded offset into the constant pool must match"); + // Trampoline_stub_size should be good. + assert((uint)(offset() - stub_start_offset) <= trampoline_stub_size, "should be good size"); + assert(is_NativeCallTrampolineStub_at(stub_start_addr), "doesn't look like a trampoline"); + + // End the stub. + end_a_stub(); + return stub; +} + // TM on PPC64. void MacroAssembler::atomic_inc_ptr(Register addr, Register result, int simm16) { Label retry; @@ -2387,17 +2582,16 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register // Must fence, otherwise, preceding store(s) may float below cmpxchg. // Compare object markOop with mark and if equal exchange scratch1 with object markOop. - // CmpxchgX sets cr_reg to cmpX(current, displaced). - membar(Assembler::StoreStore); cmpxchgd(/*flag=*/flag, /*current_value=*/current_header, /*compare_value=*/displaced_header, /*exchange_value=*/box, /*where=*/oop, - MacroAssembler::MemBarAcq, + MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, MacroAssembler::cmpxchgx_hint_acquire_lock(), noreg, - &cas_failed); + &cas_failed, + /*check without membar and ldarx first*/true); assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); // If the compare-and-exchange succeeded, then we found an unlocked @@ -2410,8 +2604,7 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register // Check if the owner is self by comparing the value in the markOop of object // (current_header) with the stack pointer. sub(current_header, current_header, R1_SP); - load_const_optimized(temp, (address) (~(os::vm_page_size()-1) | - markOopDesc::lock_mask_in_place)); + load_const_optimized(temp, ~(os::vm_page_size()-1) | markOopDesc::lock_mask_in_place); and_(R0/*==0?*/, current_header, temp); // If condition is true we are cont and hence we can store 0 as the @@ -2437,8 +2630,6 @@ void MacroAssembler::compiler_fast_lock_object(ConditionRegister flag, Register // Try to CAS m->owner from NULL to current thread. addi(temp, displaced_header, ObjectMonitor::owner_offset_in_bytes()-markOopDesc::monitor_value); - li(displaced_header, 0); - // CmpxchgX sets flag to cmpX(current, displaced). cmpxchgd(/*flag=*/flag, /*current_value=*/current_header, /*compare_value=*/(intptr_t)0, @@ -2928,31 +3119,12 @@ void MacroAssembler::load_klass(Register dst, Register src) { } } -void MacroAssembler::load_klass_with_trap_null_check(Register dst, Register src) { - if (!os::zero_page_read_protected()) { - if (TrapBasedNullChecks) { - trap_null_check(src); - } - } - load_klass(dst, src); -} - -void MacroAssembler::reinit_heapbase(Register d, Register tmp) { - if (Universe::heap() != NULL) { - load_const_optimized(R30, Universe::narrow_ptrs_base(), tmp); - } else { - // Heap not yet allocated. Load indirectly. - int simm16_offset = load_const_optimized(R30, Universe::narrow_ptrs_base_addr(), tmp, true); - ld(R30, simm16_offset, R30); - } -} - // Clear Array // Kills both input registers. tmp == R0 is allowed. void MacroAssembler::clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp) { // Procedure for large arrays (uses data cache block zero instruction). Label startloop, fast, fastloop, small_rest, restloop, done; - const int cl_size = VM_Version::get_cache_line_size(), + const int cl_size = VM_Version::L1_data_cache_line_size(), cl_dwords = cl_size>>3, cl_dw_addr_bits = exact_log2(cl_dwords), dcbz_min = 1; // Min count of dcbz executions, needs to be >0. @@ -4025,7 +4197,7 @@ void MacroAssembler::multiply_128_x_128_loop(Register x_xstart, bind(L_check_1); addi(idx, idx, 0x2); - andi_(idx, idx, 0x1) ; + andi_(idx, idx, 0x1); addic_(idx, idx, -1); blt(CCR0, L_post_third_loop_done); @@ -4255,17 +4427,42 @@ void MacroAssembler::verify_oop(Register oop, const char* msg) { address/* FunctionDescriptor** */fd = StubRoutines::verify_oop_subroutine_entry_address(); const Register tmp = R11; // Will be preserved. - const int nbytes_save = 11*8; // Volatile gprs except R0. + const int nbytes_save = MacroAssembler::num_volatile_regs * 8; save_volatile_gprs(R1_SP, -nbytes_save); // except R0 - if (oop == tmp) mr(R4_ARG2, oop); + mr_if_needed(R4_ARG2, oop); + save_LR_CR(tmp); // save in old frame + push_frame_reg_args(nbytes_save, tmp); + // load FunctionDescriptor** / entry_address * + load_const_optimized(tmp, fd, R0); + // load FunctionDescriptor* / entry_address + ld(tmp, 0, tmp); + load_const_optimized(R3_ARG1, (address)msg, R0); + // Call destination for its side effect. + call_c(tmp); + + pop_frame(); + restore_LR_CR(tmp); + restore_volatile_gprs(R1_SP, -nbytes_save); // except R0 +} + +void MacroAssembler::verify_oop_addr(RegisterOrConstant offs, Register base, const char* msg) { + if (!VerifyOops) { + return; + } + + address/* FunctionDescriptor** */fd = StubRoutines::verify_oop_subroutine_entry_address(); + const Register tmp = R11; // Will be preserved. + const int nbytes_save = MacroAssembler::num_volatile_regs * 8; + save_volatile_gprs(R1_SP, -nbytes_save); // except R0 + + ld(R4_ARG2, offs, base); save_LR_CR(tmp); // save in old frame push_frame_reg_args(nbytes_save, tmp); // load FunctionDescriptor** / entry_address * load_const_optimized(tmp, fd, R0); // load FunctionDescriptor* / entry_address ld(tmp, 0, tmp); - if (oop != tmp) mr_if_needed(R4_ARG2, oop); load_const_optimized(R3_ARG1, (address)msg, R0); // Call destination for its side effect. call_c(tmp); diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp index 37930a4bfc2..df58832b160 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -119,11 +119,8 @@ class MacroAssembler: public Assembler { // Emits an oop const to the constant pool, loads the constant, and // sets a relocation info with address current_pc. - void load_const_from_method_toc(Register dst, AddressLiteral& a, Register toc); - void load_toc_from_toc(Register dst, AddressLiteral& a, Register toc) { - assert(dst == R2_TOC, "base register must be TOC"); - load_const_from_method_toc(dst, a, toc); - } + // Returns true if successful. + bool load_const_from_method_toc(Register dst, AddressLiteral& a, Register toc, bool fixed_size = false); static bool is_load_const_from_method_toc_at(address a); static int get_offset_of_load_const_from_method_toc_at(address a); @@ -174,6 +171,7 @@ class MacroAssembler: public Assembler { // optimize: flag for telling the conditional far branch to optimize // itself when relocated. void bc_far(int boint, int biint, Label& dest, int optimize); + void bc_far_optimized(int boint, int biint, Label& dest); // 1 or 2 instructions // Relocation of conditional far branches. static bool is_bc_far_at(address instruction_addr); static address get_dest_of_bc_far_at(address instruction_addr); @@ -262,6 +260,7 @@ class MacroAssembler: public Assembler { // some ABI-related functions void save_nonvolatile_gprs( Register dst_base, int offset); void restore_nonvolatile_gprs(Register src_base, int offset); + enum { num_volatile_regs = 11 + 14 }; // GPR + FPR void save_volatile_gprs( Register dst_base, int offset); void restore_volatile_gprs(Register src_base, int offset); void save_LR_CR( Register tmp); // tmp contains LR on return. @@ -461,8 +460,10 @@ class MacroAssembler: public Assembler { Register super_klass, Register temp1_reg, Register temp2_reg, - Label& L_success, - Label& L_failure); + Label* L_success, + Label* L_failure, + Label* L_slow_path = NULL, // default fall through + RegisterOrConstant super_check_offset = RegisterOrConstant(-1)); // The rest of the type check; must be wired to a corresponding fast path. // It does not repeat the fast path logic, so don't use it standalone. @@ -507,6 +508,28 @@ class MacroAssembler: public Assembler { // biased locking exit case failed. void biased_locking_exit(ConditionRegister cr_reg, Register mark_addr, Register temp_reg, Label& done); + // allocation (for C1) + void eden_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Register t2, // temp register + Label& slow_case // continuation point if fast allocation fails + ); + void tlab_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register t1, // temp register + Label& slow_case // continuation point if fast allocation fails + ); + void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case); + void incr_allocated_bytes(RegisterOrConstant size_in_bytes, Register t1, Register t2); + + enum { trampoline_stub_size = 6 * 4 }; + address emit_trampoline_stub(int destination_toc_offset, int insts_call_instruction_offset, Register Rtoc = noreg); + void atomic_inc_ptr(Register addr, Register result, int simm16 = 1); void atomic_ori_int(Register addr, Register result, int uimm16); @@ -597,9 +620,7 @@ class MacroAssembler: public Assembler { // Implicit or explicit null check, jumps to static address exception_entry. inline void null_check_throw(Register a, int offset, Register temp_reg, address exception_entry); - - // Check accessed object for null. Use SIGTRAP-based null checks on AIX. - inline void load_with_trap_null_check(Register d, int si16, Register s1); + inline void null_check(Register a, int offset, Label *Lis_null); // implicit only if Lis_null not provided // Load heap oop and decompress. Loaded oop may not be null. // Specify tmp to save one cycle. @@ -619,20 +640,17 @@ class MacroAssembler: public Assembler { inline Register decode_heap_oop_not_null(Register d, Register src = noreg); // Null allowed. + inline Register encode_heap_oop(Register d, Register src); // Prefer null check in GC barrier! inline void decode_heap_oop(Register d); // Load/Store klass oop from klass field. Compress. void load_klass(Register dst, Register src); - void load_klass_with_trap_null_check(Register dst, Register src); void store_klass(Register dst_oop, Register klass, Register tmp = R0); void store_klass_gap(Register dst_oop, Register val = noreg); // Will store 0 if val not specified. static int instr_size_for_decode_klass_not_null(); void decode_klass_not_null(Register dst, Register src = noreg); Register encode_klass_not_null(Register dst, Register src = noreg); - // Load common heap base into register. - void reinit_heapbase(Register d, Register tmp = noreg); - // SIGTRAP-based range checks for arrays. inline void trap_range_check_l(Register a, Register b); inline void trap_range_check_l(Register a, int si16); @@ -750,6 +768,7 @@ class MacroAssembler: public Assembler { // Emit code to verify that reg contains a valid oop if +VerifyOops is set. void verify_oop(Register reg, const char* s = "broken oop"); + void verify_oop_addr(RegisterOrConstant offs, Register base, const char* s = "contains broken oop"); // TODO: verify method and klass metadata (compare against vptr?) void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {} diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp index 9d062d799c7..62843482074 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.inline.hpp @@ -70,9 +70,11 @@ inline void MacroAssembler::endgroup_if_needed(bool needed) { } inline void MacroAssembler::membar(int bits) { - // TODO: use elemental_membar(bits) for Power 8 and disable optimization of acquire-release - // (Matcher::post_membar_release where we use PPC64_ONLY(xop == Op_MemBarRelease ||)) - if (bits & StoreLoad) sync(); else lwsync(); + // Comment: Usage of elemental_membar(bits) is not recommended for Power 8. + // If elemental_membar(bits) is used, disable optimization of acquire-release + // (Matcher::post_membar_release where we use PPC64_ONLY(xop == Op_MemBarRelease ||))! + if (bits & StoreLoad) { sync(); } + else if (bits) { lwsync(); } } inline void MacroAssembler::release() { membar(LoadStore | StoreStore); } inline void MacroAssembler::acquire() { membar(LoadLoad | LoadStore); } @@ -86,7 +88,7 @@ inline address MacroAssembler::global_toc() { // Offset of given address to the global TOC. inline int MacroAssembler::offset_to_global_toc(const address addr) { intptr_t offset = (intptr_t)addr - (intptr_t)MacroAssembler::global_toc(); - assert(Assembler::is_simm((long)offset, 31) && offset >= 0, "must be in range"); + assert(Assembler::is_uimm((long)offset, 31), "must be in range"); return (int)offset; } @@ -98,7 +100,7 @@ inline address MacroAssembler::method_toc() { // Offset of given address to current method's TOC. inline int MacroAssembler::offset_to_method_toc(address addr) { intptr_t offset = (intptr_t)addr - (intptr_t)method_toc(); - assert(is_simm((long)offset, 31) && offset >= 0, "must be in range"); + assert(Assembler::is_uimm((long)offset, 31), "must be in range"); return (int)offset; } @@ -190,13 +192,13 @@ inline bool MacroAssembler::is_bc_far_variant1_at(address instruction_addr) { // Variant 1, the 1st instruction contains the destination address: // // bcxx DEST - // endgroup + // nop // const int instruction_1 = *(int*)(instruction_addr); const int instruction_2 = *(int*)(instruction_addr + 4); return is_bcxx(instruction_1) && (inv_bd_field(instruction_1, (intptr_t)instruction_addr) != (intptr_t)(instruction_addr + 2*4)) && - is_endgroup(instruction_2); + is_nop(instruction_2); } // Relocation of conditional far branches. @@ -302,13 +304,17 @@ inline void MacroAssembler::null_check_throw(Register a, int offset, Register te } } -inline void MacroAssembler::load_with_trap_null_check(Register d, int si16, Register s1) { - if (!os::zero_page_read_protected()) { +inline void MacroAssembler::null_check(Register a, int offset, Label *Lis_null) { + if (!ImplicitNullChecks || needs_explicit_null_check(offset) || !os::zero_page_read_protected()) { if (TrapBasedNullChecks) { - trap_null_check(s1); + assert(UseSIGTRAP, "sanity"); + trap_null_check(a); + } else if (Lis_null){ + Label ok; + cmpdi(CCR0, a, 0); + beq(CCR0, *Lis_null); } } - ld(d, si16, s1); } inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1, Register tmp) { @@ -365,6 +371,26 @@ inline Register MacroAssembler::encode_heap_oop_not_null(Register d, Register sr return current; // Encoded oop is in this register. } +inline Register MacroAssembler::encode_heap_oop(Register d, Register src) { + if (Universe::narrow_oop_base() != NULL) { + if (VM_Version::has_isel()) { + cmpdi(CCR0, src, 0); + Register co = encode_heap_oop_not_null(d, src); + assert(co == d, "sanity"); + isel_0(d, CCR0, Assembler::equal); + } else { + Label isNull; + or_(d, src, src); // move and compare 0 + beq(CCR0, isNull); + encode_heap_oop_not_null(d, src); + bind(isNull); + } + return d; + } else { + return encode_heap_oop_not_null(d, src); + } +} + inline Register MacroAssembler::decode_heap_oop_not_null(Register d, Register src) { if (Universe::narrow_oop_base_disjoint() && src != noreg && src != d && Universe::narrow_oop_shift() != 0) { diff --git a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp index fed5e53c206..4a743eed8be 100644 --- a/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/methodHandles_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -504,8 +504,7 @@ void trace_method_handle_stub(const char* adaptername, frame cur_frame = os::current_frame(); // Robust search of trace_calling_frame (independant of inlining). - // Assumes saved_regs comes from a pusha in the trace_calling_frame. - assert(cur_frame.sp() < saved_regs, "registers not saved on stack ?"); + assert(cur_frame.sp() <= saved_regs, "registers not saved on stack ?"); frame trace_calling_frame = os::get_sender_for_C_frame(&cur_frame); while (trace_calling_frame.fp() < saved_regs) { trace_calling_frame = os::get_sender_for_C_frame(&trace_calling_frame); @@ -539,7 +538,7 @@ void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adapt BLOCK_COMMENT("trace_method_handle {"); const Register tmp = R11; // Will be preserved. - const int nbytes_save = 11*8; // volatile gprs except R0 + const int nbytes_save = MacroAssembler::num_volatile_regs * 8; __ save_volatile_gprs(R1_SP, -nbytes_save); // except R0 __ save_LR_CR(tmp); // save in old frame diff --git a/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp b/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp index ecca49af2ef..37956925d0d 100644 --- a/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/nativeInst_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,13 +65,17 @@ address NativeCall::destination() const { address destination = Assembler::bxx_destination(addr); // Do we use a trampoline stub for this call? - CodeBlob* cb = CodeCache::find_blob_unsafe(addr); // Else we get assertion if nmethod is zombie. - assert(cb && cb->is_nmethod(), "sanity"); - nmethod *nm = (nmethod *)cb; - if (nm->stub_contains(destination) && is_NativeCallTrampolineStub_at(destination)) { - // Yes we do, so get the destination from the trampoline stub. - const address trampoline_stub_addr = destination; - destination = NativeCallTrampolineStub_at(trampoline_stub_addr)->destination(nm); + // Trampoline stubs are located behind the main code. + if (destination > addr) { + // Filter out recursive method invocation (call to verified/unverified entry point). + CodeBlob* cb = CodeCache::find_blob_unsafe(addr); // Else we get assertion if nmethod is zombie. + assert(cb && cb->is_nmethod(), "sanity"); + nmethod *nm = (nmethod *)cb; + if (nm->stub_contains(destination) && is_NativeCallTrampolineStub_at(destination)) { + // Yes we do, so get the destination from the trampoline stub. + const address trampoline_stub_addr = destination; + destination = NativeCallTrampolineStub_at(trampoline_stub_addr)->destination(nm); + } } return destination; @@ -267,7 +271,7 @@ void NativeMovConstReg::set_data(intptr_t data) { oop_addr = r->oop_addr(); *oop_addr = cast_to_oop(data); } else { - assert(oop_addr == r->oop_addr(), "must be only one set-oop here") ; + assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); } } if (iter.type() == relocInfo::metadata_type) { @@ -351,6 +355,27 @@ void NativeJump::verify() { } #endif // ASSERT + +void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { + CodeBuffer cb(code_pos, BytesPerInstWord + 1); + MacroAssembler* a = new MacroAssembler(&cb); + a->b(entry); + ICache::ppc64_flush_icache_bytes(code_pos, NativeGeneralJump::instruction_size); +} + +// MT-safe patching of a jmp instruction. +void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) { + // Bytes beyond offset NativeGeneralJump::instruction_size are copied by caller. + + // Finally patch out the jump. + volatile juint *jump_addr = (volatile juint*)instr_addr; + // Release not needed because caller uses invalidate_range after copying the remaining bytes. + //OrderAccess::release_store(jump_addr, *((juint*)code_buffer)); + *jump_addr = *((juint*)code_buffer); // atomically store code over branch instruction + ICache::ppc64_flush_icache_bytes(instr_addr, NativeGeneralJump::instruction_size); +} + + //------------------------------------------------------------------- // Call trampoline stubs. @@ -364,10 +389,12 @@ void NativeJump::verify() { // address NativeCallTrampolineStub::encoded_destination_addr() const { - address instruction_addr = addr_at(2 * BytesPerInstWord); - assert(MacroAssembler::is_ld_largeoffset(instruction_addr), - "must be a ld with large offset (from the constant pool)"); - + address instruction_addr = addr_at(0 * BytesPerInstWord); + if (!MacroAssembler::is_ld_largeoffset(instruction_addr)) { + instruction_addr = addr_at(2 * BytesPerInstWord); + assert(MacroAssembler::is_ld_largeoffset(instruction_addr), + "must be a ld with large offset (from the constant pool)"); + } return instruction_addr; } diff --git a/hotspot/src/cpu/ppc/vm/nativeInst_ppc.hpp b/hotspot/src/cpu/ppc/vm/nativeInst_ppc.hpp index 0ef57be0556..f0f6b6a87d9 100644 --- a/hotspot/src/cpu/ppc/vm/nativeInst_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/nativeInst_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2013 SAP AG. All rights reserved. + * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,6 +50,8 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { friend class Relocation; public: + bool is_jump() { return Assembler::is_b(long_at(0)); } // See NativeGeneralJump. + bool is_sigtrap_ic_miss_check() { assert(UseSIGTRAP, "precondition"); return MacroAssembler::is_trap_ic_miss_check(long_at(0)); @@ -235,8 +237,8 @@ inline NativeFarCall* nativeFarCall_at(address instr) { return call; } -// An interface for accessing/manipulating native set_oop imm, reg instructions. -// (used to manipulate inlined data references, etc.) +// An interface for accessing/manipulating native set_oop imm, reg instructions +// (used to manipulate inlined data references, etc.). class NativeMovConstReg: public NativeInstruction { public: @@ -384,10 +386,21 @@ class NativeCallTrampolineStub : public NativeInstruction { void set_destination(address new_destination); }; +// Note: Other stubs must not begin with this pattern. inline bool is_NativeCallTrampolineStub_at(address address) { int first_instr = *(int*)address; - return Assembler::is_addis(first_instr) && - (Register)(intptr_t)Assembler::inv_rt_field(first_instr) == R12_scratch2; + // calculate_address_from_global_toc and long form of ld_largeoffset_unchecked begin with addis with target R12 + if (Assembler::is_addis(first_instr) && + (Register)(intptr_t)Assembler::inv_rt_field(first_instr) == R12_scratch2) return true; + + // short form of ld_largeoffset_unchecked is ld which is followed by mtctr + int second_instr = *((int*)address + 1); + if (Assembler::is_ld(first_instr) && + (Register)(intptr_t)Assembler::inv_rt_field(first_instr) == R12_scratch2 && + Assembler::is_mtctr(second_instr) && + (Register)(intptr_t)Assembler::inv_rs_field(second_instr) == R12_scratch2) return true; + + return false; } inline NativeCallTrampolineStub* NativeCallTrampolineStub_at(address address) { @@ -395,4 +408,102 @@ inline NativeCallTrampolineStub* NativeCallTrampolineStub_at(address address) { return (NativeCallTrampolineStub*)address; } +/////////////////////////////////////////////////////////////////////////////////////////////////// + +//------------------------------------- +// N a t i v e G e n e r a l J u m p +//------------------------------------- + +// Despite the name, handles only simple branches. +class NativeGeneralJump; +inline NativeGeneralJump* nativeGeneralJump_at(address address); + +// Currently only implemented as single unconditional branch. +class NativeGeneralJump: public NativeInstruction { + public: + + enum PPC64_specific_constants { + instruction_size = 4 + }; + + address instruction_address() const { return addr_at(0); } + + // Creation. + friend inline NativeGeneralJump* nativeGeneralJump_at(address addr) { + NativeGeneralJump* jump = (NativeGeneralJump*)(addr); + DEBUG_ONLY( jump->verify(); ) + return jump; + } + + // Insertion of native general jump instruction. + static void insert_unconditional(address code_pos, address entry); + + address jump_destination() const { + DEBUG_ONLY( verify(); ) + return addr_at(0) + Assembler::inv_li_field(long_at(0)); + } + + void set_jump_destination(address dest) { + DEBUG_ONLY( verify(); ) + insert_unconditional(addr_at(0), dest); + } + + static void replace_mt_safe(address instr_addr, address code_buffer); + + void verify() const { guarantee(Assembler::is_b(long_at(0)), "invalid NativeGeneralJump"); } +}; + +// An interface for accessing/manipulating native load int (load_const32). +class NativeMovRegMem; +inline NativeMovRegMem* nativeMovRegMem_at(address address); +class NativeMovRegMem: public NativeInstruction { + public: + + enum PPC64_specific_constants { + instruction_size = 8 + }; + + address instruction_address() const { return addr_at(0); } + + intptr_t offset() const { +#ifdef VM_LITTLE_ENDIAN + short *hi_ptr = (short*)(addr_at(0)); + short *lo_ptr = (short*)(addr_at(4)); +#else + short *hi_ptr = (short*)(addr_at(0) + 2); + short *lo_ptr = (short*)(addr_at(4) + 2); +#endif + return ((*hi_ptr) << 16) | ((*lo_ptr) & 0xFFFF); + } + + void set_offset(intptr_t x) { +#ifdef VM_LITTLE_ENDIAN + short *hi_ptr = (short*)(addr_at(0)); + short *lo_ptr = (short*)(addr_at(4)); +#else + short *hi_ptr = (short*)(addr_at(0) + 2); + short *lo_ptr = (short*)(addr_at(4) + 2); +#endif + *hi_ptr = x >> 16; + *lo_ptr = x & 0xFFFF; + ICache::ppc64_flush_icache_bytes(addr_at(0), NativeMovRegMem::instruction_size); + } + + void add_offset_in_bytes(intptr_t radd_offset) { + set_offset(offset() + radd_offset); + } + + void verify() const { + guarantee(Assembler::is_lis(long_at(0)), "load_const32 1st instr"); + guarantee(Assembler::is_ori(long_at(4)), "load_const32 2nd instr"); + } + + private: + friend inline NativeMovRegMem* nativeMovRegMem_at(address address) { + NativeMovRegMem* test = (NativeMovRegMem*)address; + DEBUG_ONLY( test->verify(); ) + return test; + } +}; + #endif // CPU_PPC_VM_NATIVEINST_PPC_HPP diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index daa35899360..aefdf28133f 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -698,7 +698,7 @@ reg_class ctr_reg(SR_CTR); // ---------------------------- reg_class flt_reg( -/*F0*/ // scratch + F0, F1, F2, F3, @@ -735,7 +735,7 @@ reg_class flt_reg( // Double precision float registers have virtual `high halves' that // are needed by the allocator. reg_class dbl_reg( -/*F0, F0_H*/ // scratch + F0, F0_H, F1, F1_H, F2, F2_H, F3, F3_H, @@ -1040,8 +1040,6 @@ source_hpp %{ // Header information of the source block. //---< Used for optimization in Compile::Shorten_branches >--- //-------------------------------------------------------------- -const uint trampoline_stub_size = 6 * BytesPerInstWord; - class CallStubImpl { public: @@ -1053,7 +1051,7 @@ class CallStubImpl { // This doesn't need to be accurate to the byte, but it // must be larger than or equal to the real size of the stub. static uint size_call_trampoline() { - return trampoline_stub_size; + return MacroAssembler::trampoline_stub_size; } // number of relocations needed by a call trampoline stub @@ -1079,46 +1077,10 @@ source %{ // branch via CTR (LR/link still points to the call-site above) void CallStubImpl::emit_trampoline_stub(MacroAssembler &_masm, int destination_toc_offset, int insts_call_instruction_offset) { - // Start the stub. - address stub = __ start_a_stub(Compile::MAX_stubs_size/2); + address stub = __ emit_trampoline_stub(destination_toc_offset, insts_call_instruction_offset); if (stub == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); - return; + ciEnv::current()->record_out_of_memory_failure(); } - - // For java_to_interp stubs we use R11_scratch1 as scratch register - // and in call trampoline stubs we use R12_scratch2. This way we - // can distinguish them (see is_NativeCallTrampolineStub_at()). - Register reg_scratch = R12_scratch2; - - // Create a trampoline stub relocation which relates this trampoline stub - // with the call instruction at insts_call_instruction_offset in the - // instructions code-section. - __ relocate(trampoline_stub_Relocation::spec(__ code()->insts()->start() + insts_call_instruction_offset)); - const int stub_start_offset = __ offset(); - - // Now, create the trampoline stub's code: - // - load the TOC - // - load the call target from the constant pool - // - call - __ calculate_address_from_global_toc(reg_scratch, __ method_toc()); - __ ld_largeoffset_unchecked(reg_scratch, destination_toc_offset, reg_scratch, false); - __ mtctr(reg_scratch); - __ bctr(); - - const address stub_start_addr = __ addr_at(stub_start_offset); - - // FIXME: Assert that the trampoline stub can be identified and patched. - - // Assert that the encoded destination_toc_offset can be identified and that it is correct. - assert(destination_toc_offset == NativeCallTrampolineStub_at(stub_start_addr)->destination_toc_offset(), - "encoded offset into the constant pool must match"); - // Trampoline_stub_size should be good. - assert((uint)(__ offset() - stub_start_offset) <= trampoline_stub_size, "should be good size"); - assert(is_NativeCallTrampolineStub_at(stub_start_addr), "doesn't look like a trampoline"); - - // End the stub. - __ end_a_stub(); } //============================================================================= @@ -1156,6 +1118,10 @@ EmitCallOffsets emit_call_with_trampoline_stub(MacroAssembler &_masm, address en if (!Compile::current()->in_scratch_emit_size()) { // Put the entry point as a constant into the constant pool. const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none); + if (entry_point_toc_addr == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return offsets; + } const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); // Emit the trampoline stub which will be related to the branch-and-link below. @@ -2474,6 +2440,10 @@ encode %{ // Create a non-oop constant, no relocation needed. // If it is an IC, it has a virtual_call_Relocation. const_toc_addr = __ long_constant((jlong)$src$$constant); + if (const_toc_addr == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } // Get the constant's TOC offset. toc_offset = __ offset_to_method_toc(const_toc_addr); @@ -2495,6 +2465,10 @@ encode %{ // Create a non-oop constant, no relocation needed. // If it is an IC, it has a virtual_call_Relocation. const_toc_addr = __ long_constant((jlong)$src$$constant); + if (const_toc_addr == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } // Get the constant's TOC offset. const int toc_offset = __ offset_to_method_toc(const_toc_addr); @@ -2631,6 +2605,10 @@ encode %{ const_toc_addr = __ long_constant((jlong)$src$$constant); } + if (const_toc_addr == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } // Get the constant's TOC offset. toc_offset = __ offset_to_method_toc(const_toc_addr); } @@ -2660,6 +2638,10 @@ encode %{ const_toc_addr = __ long_constant((jlong)$src$$constant); } + if (const_toc_addr == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } // Get the constant's TOC offset. const int toc_offset = __ offset_to_method_toc(const_toc_addr); // Store the toc offset of the constant. @@ -3408,6 +3390,10 @@ encode %{ // Put the entry point as a constant into the constant pool. const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none); + if (entry_point_toc_addr == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); // Emit the trampoline stub which will be related to the branch-and-link below. @@ -3433,76 +3419,6 @@ encode %{ } %} - // Emit a method handle call. - // - // Method handle calls from compiled to compiled are going thru a - // c2i -> i2c adapter, extending the frame for their arguments. The - // caller however, returns directly to the compiled callee, that has - // to cope with the extended frame. We restore the original frame by - // loading the callers sp and adding the calculated framesize. - enc_class enc_java_handle_call(method meth) %{ - // TODO: PPC port $archOpcode(ppc64Opcode_compound); - - MacroAssembler _masm(&cbuf); - address entry_point = (address)$meth$$method; - - // Remember the offset not the address. - const int start_offset = __ offset(); - // The trampoline stub. - if (!ra_->C->in_scratch_emit_size()) { - // No entry point given, use the current pc. - // Make sure branch fits into - if (entry_point == 0) entry_point = __ pc(); - - // Put the entry point as a constant into the constant pool. - const address entry_point_toc_addr = __ address_constant(entry_point, RelocationHolder::none); - const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); - - // Emit the trampoline stub which will be related to the branch-and-link below. - CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); - if (ra_->C->env()->failing()) { return; } // Code cache may be full. - assert(_optimized_virtual, "methodHandle call should be a virtual call"); - __ relocate(relocInfo::opt_virtual_call_type); - } - - // The real call. - // Note: At this point we do not have the address of the trampoline - // stub, and the entry point might be too far away for bl, so __ pc() - // serves as dummy and the bl will be patched later. - cbuf.set_insts_mark(); - __ bl(__ pc()); // Emits a relocation. - - assert(_method, "execute next statement conditionally"); - // The stub for call to interpreter. - address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); - if (stub == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); - return; - } - - // Restore original sp. - __ ld(R11_scratch1, 0, R1_SP); // Load caller sp. - const long framesize = ra_->C->frame_slots() << LogBytesPerInt; - unsigned int bytes = (unsigned int)framesize; - long offset = Assembler::align_addr(bytes, frame::alignment_in_bytes); - if (Assembler::is_simm(-offset, 16)) { - __ addi(R1_SP, R11_scratch1, -offset); - } else { - __ load_const_optimized(R12_scratch2, -offset); - __ add(R1_SP, R11_scratch1, R12_scratch2); - } -#ifdef ASSERT - __ ld(R12_scratch2, 0, R1_SP); // Load from unextended_sp. - __ cmpd(CCR0, R11_scratch1, R12_scratch2); - __ asm_assert_eq("backlink changed", 0x8000); -#endif - // If fails should store backlink before unextending. - - if (ra_->C->env()->failing()) { - return; - } - %} - // Second node of expanded dynamic call - the call. enc_class enc_java_dynamic_call_sched(method meth) %{ // TODO: PPC port $archOpcode(ppc64Opcode_bl); @@ -3513,6 +3429,10 @@ encode %{ // Create a call trampoline stub for the given method. const address entry_point = !($meth$$method) ? 0 : (address)$meth$$method; const address entry_point_const = __ address_constant(entry_point, RelocationHolder::none); + if (entry_point_const == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } const int entry_point_const_toc_offset = __ offset_to_method_toc(entry_point_const); CallStubImpl::emit_trampoline_stub(_masm, entry_point_const_toc_offset, __ offset()); if (ra_->C->env()->failing()) { return; } // Code cache may be full. @@ -3620,7 +3540,11 @@ encode %{ address virtual_call_meta_addr = __ pc(); // Load a clear inline cache. AddressLiteral empty_ic((address) Universe::non_oop_word()); - __ load_const_from_method_toc(ic_reg, empty_ic, Rtoc); + bool success = __ load_const_from_method_toc(ic_reg, empty_ic, Rtoc, /*fixed_size*/ true); + if (!success) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } // CALL to fixup routine. Fixup routine uses ScopeDesc info // to determine who we intended to call. __ relocate(virtual_call_Relocation::spec(virtual_call_meta_addr)); @@ -3676,7 +3600,11 @@ encode %{ __ calculate_address_from_global_toc(Rtoc, __ method_toc()); // Put entry, env, toc into the constant pool, this needs up to 3 constant // pool entries; call_c_using_toc will optimize the call. - __ call_c_using_toc(fd, relocInfo::runtime_call_type, Rtoc); + bool success = __ call_c_using_toc(fd, relocInfo::runtime_call_type, Rtoc); + if (!success) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } #endif // Check the ret_addr_offset. @@ -6263,6 +6191,10 @@ instruct loadConF(regF dst, immF src, iRegLdst toc) %{ ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_lfs); address float_address = __ float_constant($src$$constant); + if (float_address == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } __ lfs($dst$$FloatRegister, __ offset_to_method_toc(float_address), $toc$$Register); %} ins_pipe(pipe_class_memory); @@ -6284,6 +6216,10 @@ instruct loadConFComp(regF dst, immF src, iRegLdst toc) %{ FloatRegister Rdst = $dst$$FloatRegister; Register Rtoc = $toc$$Register; address float_address = __ float_constant($src$$constant); + if (float_address == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } int offset = __ offset_to_method_toc(float_address); int hi = (offset + (1<<15))>>16; int lo = offset - hi * (1<<16); @@ -6318,7 +6254,12 @@ instruct loadConD(regD dst, immD src, iRegLdst toc) %{ size(4); ins_encode %{ // TODO: PPC port $archOpcode(ppc64Opcode_lfd); - int offset = __ offset_to_method_toc(__ double_constant($src$$constant)); + address float_address = __ double_constant($src$$constant); + if (float_address == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } + int offset = __ offset_to_method_toc(float_address); __ lfd($dst$$FloatRegister, offset, $toc$$Register); %} ins_pipe(pipe_class_memory); @@ -6340,7 +6281,11 @@ instruct loadConDComp(regD dst, immD src, iRegLdst toc) %{ FloatRegister Rdst = $dst$$FloatRegister; Register Rtoc = $toc$$Register; address float_address = __ double_constant($src$$constant); - int offset = __ offset_to_method_toc(float_address); + if (float_address == NULL) { + ciEnv::current()->record_out_of_memory_failure(); + return; + } + int offset = __ offset_to_method_toc(float_address); int hi = (offset + (1<<15))>>16; int lo = offset - hi * (1<<16); @@ -11790,7 +11735,6 @@ instruct safePoint_poll_conPollAddr(rscratch2RegP poll) %{ instruct CallStaticJavaDirect(method meth) %{ match(CallStaticJava); effect(USE meth); - predicate(!((CallStaticJavaNode*)n)->is_method_handle_invoke()); ins_cost(CALL_COST); ins_num_consts(3 /* up to 3 patchable constants: inline cache, 2 call targets. */); @@ -11801,20 +11745,6 @@ instruct CallStaticJavaDirect(method meth) %{ ins_pipe(pipe_class_call); %} -// Schedulable version of call static node. -instruct CallStaticJavaDirectHandle(method meth) %{ - match(CallStaticJava); - effect(USE meth); - predicate(((CallStaticJavaNode*)n)->is_method_handle_invoke()); - ins_cost(CALL_COST); - - ins_num_consts(3 /* up to 3 patchable constants: inline cache, 2 call targets. */); - - format %{ "CALL,static $meth \t// ==> " %} - ins_encode( enc_java_handle_call(meth) ); - ins_pipe(pipe_class_call); -%} - // Call Java Dynamic Instruction // Used by postalloc expand of CallDynamicJavaDirectSchedEx (actual call). diff --git a/hotspot/src/cpu/ppc/vm/register_ppc.hpp b/hotspot/src/cpu/ppc/vm/register_ppc.hpp index 9dc765ab4a2..1d0eeac61a2 100644 --- a/hotspot/src/cpu/ppc/vm/register_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/register_ppc.hpp @@ -627,6 +627,9 @@ REGISTER_DECLARATION(Register, R27_constPoolCache, R27); REGISTER_DECLARATION(Register, R28_mdx, R28); #endif // CC_INTERP +REGISTER_DECLARATION(Register, R19_inline_cache_reg, R19); +REGISTER_DECLARATION(Register, R29_TOC, R29); + #ifndef DONT_USE_REGISTER_DEFINES #define R21_tmp1 AS_REGISTER(Register, R21) #define R22_tmp2 AS_REGISTER(Register, R22) @@ -648,6 +651,9 @@ REGISTER_DECLARATION(Register, R28_mdx, R28); #define R28_mdx AS_REGISTER(Register, R28) #endif +#define R19_inline_cache_reg AS_REGISTER(Register, R19) +#define R29_TOC AS_REGISTER(Register, R29) + #define CCR4_is_synced AS_REGISTER(ConditionRegister, CCR4) #endif diff --git a/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp b/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp index 74e72ba62b6..9c5065d0dd4 100644 --- a/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/relocInfo_ppc.cpp @@ -84,13 +84,11 @@ address Relocation::pd_call_destination(address orig_addr) { NativeConditionalFarBranch* branch = NativeConditionalFarBranch_at(inst_loc); return branch->branch_destination(); } else { - // There are two instructions at the beginning of a stub, therefore we - // load at orig_addr + 8. orig_addr = nativeCall_at(inst_loc)->get_trampoline(); if (orig_addr == NULL) { return (address) -1; } else { - return (address) nativeMovConstReg_at(orig_addr + 8)->data(); + return ((NativeCallTrampolineStub*)orig_addr)->destination(); } } } diff --git a/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp b/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp index 404df938777..e887877d14e 100644 --- a/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/runtime_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. - * Copyright 2012, 2014 SAP AG. All rights reserved. + * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. * 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,16 +45,6 @@ #ifdef COMPILER2 -// SP adjustment (must use unextended SP) for method handle call sites -// during exception handling. -static intptr_t adjust_SP_for_methodhandle_callsite(JavaThread *thread) { - RegisterMap map(thread, false); - // The frame constructor will do the correction for us (see frame::adjust_unextended_SP). - frame mh_caller_frame = thread->last_frame().sender(&map); - assert(mh_caller_frame.is_compiled_frame(), "Only may reach here for compiled MH call sites"); - return (intptr_t) mh_caller_frame.unextended_sp(); -} - //------------------------------generate_exception_blob--------------------------- // Creates exception blob at the end. // Using exception blob, this code is jumped from a compiled method. @@ -129,17 +119,10 @@ void OptoRuntime::generate_exception_blob() { OopMapSet* oop_maps = new OopMapSet(); oop_maps->add_gc_map(calls_return_pc - start, map); - // Get unextended_sp for method handle call sites. - Label mh_callsite, mh_done; // Use a 2nd c call if it's a method handle call site. - __ lwa(R4_ARG2, in_bytes(JavaThread::is_method_handle_return_offset()), R16_thread); - __ cmpwi(CCR0, R4_ARG2, 0); - __ bne(CCR0, mh_callsite); - __ mtctr(R3_RET); // Move address of exception handler to SR_CTR. __ reset_last_Java_frame(); __ pop_frame(); - __ bind(mh_done); // We have a handler in register SR_CTR (could be deopt blob). // Get the exception oop. @@ -161,25 +144,6 @@ void OptoRuntime::generate_exception_blob() { __ mtlr(R4_ARG2); __ bctr(); - - // Same as above, but also set sp to unextended_sp. - __ bind(mh_callsite); - __ mr(R31, R3_RET); // Save branch address. - __ mr(R3_ARG1, R16_thread); -#if defined(ABI_ELFv2) - __ call_c((address) adjust_SP_for_methodhandle_callsite, relocInfo::none); -#else - __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, adjust_SP_for_methodhandle_callsite), relocInfo::none); -#endif - // Returns unextended_sp in R3_RET. - - __ mtctr(R31); // Move address of exception handler to SR_CTR. - __ reset_last_Java_frame(); - - __ mr(R1_SP, R3_RET); // Set sp to unextended_sp. - __ b(mh_done); - - // Make sure all code is generated. masm->flush(); diff --git a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp index 141891d0a16..ec9f568516e 100644 --- a/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/sharedRuntime_ppc.cpp @@ -62,7 +62,7 @@ class RegisterSaver { // Support different return pc locations. enum ReturnPCLocation { return_pc_is_lr, - return_pc_is_r4, + return_pc_is_pre_saved, return_pc_is_thread_saved_exception_pc }; @@ -241,16 +241,17 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble __ mfcr(R31); __ std(R31, _abi(cr), R1_SP); switch (return_pc_location) { - case return_pc_is_lr: __ mflr(R31); break; - case return_pc_is_r4: __ mr(R31, R4); break; - case return_pc_is_thread_saved_exception_pc: - __ ld(R31, thread_(saved_exception_pc)); break; + case return_pc_is_lr: __ mflr(R31); break; + case return_pc_is_pre_saved: assert(return_pc_adjustment == 0, "unsupported"); break; + case return_pc_is_thread_saved_exception_pc: __ ld(R31, thread_(saved_exception_pc)); break; default: ShouldNotReachHere(); } - if (return_pc_adjustment != 0) { - __ addi(R31, R31, return_pc_adjustment); + if (return_pc_location != return_pc_is_pre_saved) { + if (return_pc_adjustment != 0) { + __ addi(R31, R31, return_pc_adjustment); + } + __ std(R31, _abi(lr), R1_SP); } - __ std(R31, _abi(lr), R1_SP); // push a new frame __ push_frame(frame_size_in_bytes, R31); @@ -646,7 +647,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, return round_to(stk, 2); } -#ifdef COMPILER2 +#if defined(COMPILER1) || defined(COMPILER2) // Calling convention for calling C code. int SharedRuntime::c_calling_convention(const BasicType *sig_bt, VMRegPair *regs, @@ -2576,7 +2577,7 @@ uint SharedRuntime::out_preserve_stack_slots() { #endif } -#ifdef COMPILER2 +#if defined(COMPILER1) || defined(COMPILER2) // Frame generation for deopt and uncommon trap blobs. static void push_skeleton_frame(MacroAssembler* masm, bool deopt, /* Read */ @@ -2734,7 +2735,7 @@ void SharedRuntime::generate_deopt_blob() { const address start = __ pc(); -#ifdef COMPILER2 +#if defined(COMPILER1) || defined(COMPILER2) // -------------------------------------------------------------------------- // Prolog for non exception case! @@ -2783,28 +2784,43 @@ void SharedRuntime::generate_deopt_blob() { BLOCK_COMMENT("Prolog for exception case"); - // The RegisterSaves doesn't need to adjust the return pc for this situation. - const int return_pc_adjustment_exception = 0; - - // Push the "unpack frame". - // Save everything in sight. - assert(R4 == R4_ARG2, "exception pc must be in r4"); - RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, - &first_frame_size_in_bytes, - /*generate_oop_map=*/ false, - return_pc_adjustment_exception, - RegisterSaver::return_pc_is_r4); - - // Deopt during an exception. Save exec mode for unpack_frames. - __ li(exec_mode_reg, Deoptimization::Unpack_exception); - // Store exception oop and pc in thread (location known to GC). // This is needed since the call to "fetch_unroll_info()" may safepoint. __ std(R3_ARG1, in_bytes(JavaThread::exception_oop_offset()), R16_thread); __ std(R4_ARG2, in_bytes(JavaThread::exception_pc_offset()), R16_thread); + __ std(R4_ARG2, _abi(lr), R1_SP); + + // Vanilla deoptimization with an exception pending in exception_oop. + int exception_in_tls_offset = __ pc() - start; + + // Push the "unpack frame". + // Save everything in sight. + RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, + &first_frame_size_in_bytes, + /*generate_oop_map=*/ false, + /*return_pc_adjustment_exception=*/ 0, + RegisterSaver::return_pc_is_pre_saved); + + // Deopt during an exception. Save exec mode for unpack_frames. + __ li(exec_mode_reg, Deoptimization::Unpack_exception); // fall through + int reexecute_offset = 0; +#ifdef COMPILER1 + __ b(exec_mode_initialized); + + // Reexecute entry, similar to c2 uncommon trap + reexecute_offset = __ pc() - start; + + RegisterSaver::push_frame_reg_args_and_save_live_registers(masm, + &first_frame_size_in_bytes, + /*generate_oop_map=*/ false, + /*return_pc_adjustment_reexecute=*/ 0, + RegisterSaver::return_pc_is_pre_saved); + __ li(exec_mode_reg, Deoptimization::Unpack_reexecute); +#endif + // -------------------------------------------------------------------------- __ BIND(exec_mode_initialized); @@ -2918,7 +2934,9 @@ void SharedRuntime::generate_deopt_blob() { int exception_offset = __ pc() - start; #endif // COMPILER2 - _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, 0, first_frame_size_in_bytes / wordSize); + _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, + reexecute_offset, first_frame_size_in_bytes / wordSize); + _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); } #ifdef COMPILER2 diff --git a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp index 1dbb5c04f29..28f2ca60425 100644 --- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp @@ -48,6 +48,12 @@ #define BLOCK_COMMENT(str) __ block_comment(str) #endif +#if defined(ABI_ELFv2) +#define STUB_ENTRY(name) StubRoutines::name() +#else +#define STUB_ENTRY(name) ((FunctionDescriptor*)StubRoutines::name())->entry() +#endif + class StubGenerator: public StubCodeGenerator { private: @@ -259,8 +265,7 @@ class StubGenerator: public StubCodeGenerator { // // global toc register - __ load_const(R29, MacroAssembler::global_toc(), R11_scratch1); - + __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R11_scratch1); // Remember the senderSP so we interpreter can pop c2i arguments off of the stack // when called via a c2i. @@ -619,14 +624,17 @@ class StubGenerator: public StubCodeGenerator { // Kills: // nothing // - void gen_write_ref_array_pre_barrier(Register from, Register to, Register count, bool dest_uninitialized, Register Rtmp1) { + void gen_write_ref_array_pre_barrier(Register from, Register to, Register count, bool dest_uninitialized, Register Rtmp1, + Register preserve1 = noreg, Register preserve2 = noreg) { BarrierSet* const bs = Universe::heap()->barrier_set(); switch (bs->kind()) { case BarrierSet::G1SATBCTLogging: // With G1, don't generate the call if we statically know that the target in uninitialized if (!dest_uninitialized) { - const int spill_slots = 4 * wordSize; - const int frame_size = frame::abi_reg_args_size + spill_slots; + int spill_slots = 3; + if (preserve1 != noreg) { spill_slots++; } + if (preserve2 != noreg) { spill_slots++; } + const int frame_size = align_size_up(frame::abi_reg_args_size + spill_slots * BytesPerWord, frame::alignment_in_bytes); Label filtered; // Is marking active? @@ -640,17 +648,23 @@ class StubGenerator: public StubCodeGenerator { __ beq(CCR0, filtered); __ save_LR_CR(R0); - __ push_frame_reg_args(spill_slots, R0); - __ std(from, frame_size - 1 * wordSize, R1_SP); - __ std(to, frame_size - 2 * wordSize, R1_SP); - __ std(count, frame_size - 3 * wordSize, R1_SP); + __ push_frame(frame_size, R0); + int slot_nr = 0; + __ std(from, frame_size - (++slot_nr) * wordSize, R1_SP); + __ std(to, frame_size - (++slot_nr) * wordSize, R1_SP); + __ std(count, frame_size - (++slot_nr) * wordSize, R1_SP); + if (preserve1 != noreg) { __ std(preserve1, frame_size - (++slot_nr) * wordSize, R1_SP); } + if (preserve2 != noreg) { __ std(preserve2, frame_size - (++slot_nr) * wordSize, R1_SP); } __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre), to, count); - __ ld(from, frame_size - 1 * wordSize, R1_SP); - __ ld(to, frame_size - 2 * wordSize, R1_SP); - __ ld(count, frame_size - 3 * wordSize, R1_SP); - __ pop_frame(); + slot_nr = 0; + __ ld(from, frame_size - (++slot_nr) * wordSize, R1_SP); + __ ld(to, frame_size - (++slot_nr) * wordSize, R1_SP); + __ ld(count, frame_size - (++slot_nr) * wordSize, R1_SP); + if (preserve1 != noreg) { __ ld(preserve1, frame_size - (++slot_nr) * wordSize, R1_SP); } + if (preserve2 != noreg) { __ ld(preserve2, frame_size - (++slot_nr) * wordSize, R1_SP); } + __ addi(R1_SP, R1_SP, frame_size); // pop_frame() __ restore_LR_CR(R0); __ bind(filtered); @@ -674,27 +688,22 @@ class StubGenerator: public StubCodeGenerator { // // The input registers and R0 are overwritten. // - void gen_write_ref_array_post_barrier(Register addr, Register count, Register tmp, bool branchToEnd) { + void gen_write_ref_array_post_barrier(Register addr, Register count, Register tmp, Register preserve = noreg) { BarrierSet* const bs = Universe::heap()->barrier_set(); switch (bs->kind()) { case BarrierSet::G1SATBCTLogging: { - if (branchToEnd) { - __ save_LR_CR(R0); - // We need this frame only to spill LR. - __ push_frame_reg_args(0, R0); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), addr, count); - __ pop_frame(); - __ restore_LR_CR(R0); - } else { - // Tail call: fake call from stub caller by branching without linking. - address entry_point = (address)CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post); - __ mr_if_needed(R3_ARG1, addr); - __ mr_if_needed(R4_ARG2, count); - __ load_const(R11, entry_point, R0); - __ call_c_and_return_to_caller(R11); - } + int spill_slots = (preserve != noreg) ? 1 : 0; + const int frame_size = align_size_up(frame::abi_reg_args_size + spill_slots * BytesPerWord, frame::alignment_in_bytes); + + __ save_LR_CR(R0); + __ push_frame(frame_size, R0); + if (preserve != noreg) { __ std(preserve, frame_size - 1 * wordSize, R1_SP); } + __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), addr, count); + if (preserve != noreg) { __ ld(preserve, frame_size - 1 * wordSize, R1_SP); } + __ addi(R1_SP, R1_SP, frame_size); // pop_frame(); + __ restore_LR_CR(R0); } break; case BarrierSet::CardTableForRS: @@ -729,12 +738,9 @@ class StubGenerator: public StubCodeGenerator { __ addi(addr, addr, 1); __ bdnz(Lstore_loop); __ bind(Lskip_loop); - - if (!branchToEnd) __ blr(); } break; case BarrierSet::ModRef: - if (!branchToEnd) __ blr(); break; default: ShouldNotReachHere(); @@ -763,8 +769,10 @@ class StubGenerator: public StubCodeGenerator { // Procedure for large arrays (uses data cache block zero instruction). Label dwloop, fast, fastloop, restloop, lastdword, done; - int cl_size=VM_Version::get_cache_line_size(), cl_dwords=cl_size>>3, cl_dwordaddr_bits=exact_log2(cl_dwords); - int min_dcbz=2; // Needs to be positive, apply dcbz only to at least min_dcbz cache lines. + int cl_size = VM_Version::L1_data_cache_line_size(); + int cl_dwords = cl_size >> 3; + int cl_dwordaddr_bits = exact_log2(cl_dwords); + int min_dcbz = 2; // Needs to be positive, apply dcbz only to at least min_dcbz cache lines. // Clear up to 128byte boundary if long enough, dword_cnt=(16-(base>>3))%16. __ dcbtst(base_ptr_reg); // Indicate write access to first cache line ... @@ -1081,7 +1089,6 @@ class StubGenerator: public StubCodeGenerator { Register tmp1 = R6_ARG4; Register tmp2 = R7_ARG5; - Label l_overlap; #ifdef ASSERT __ srdi_(tmp2, R5_ARG3, 31); __ asm_assert_eq("missing zero extend", 0xAFFE); @@ -1091,19 +1098,11 @@ class StubGenerator: public StubCodeGenerator { __ sldi(tmp2, R5_ARG3, log2_elem_size); // size in bytes __ cmpld(CCR0, R3_ARG1, R4_ARG2); // Use unsigned comparison! __ cmpld(CCR1, tmp1, tmp2); - __ crand(CCR0, Assembler::less, CCR1, Assembler::less); - __ blt(CCR0, l_overlap); // Src before dst and distance smaller than size. + __ crnand(CCR0, Assembler::less, CCR1, Assembler::less); + // Overlaps if Src before dst and distance smaller than size. + // Branch to forward copy routine otherwise (within range of 32kB). + __ bc(Assembler::bcondCRbiIs1, Assembler::bi0(CCR0, Assembler::less), no_overlap_target); - // need to copy forwards - if (__ is_within_range_of_b(no_overlap_target, __ pc())) { - __ b(no_overlap_target); - } else { - __ load_const(tmp1, no_overlap_target, tmp2); - __ mtctr(tmp1); - __ bctr(); - } - - __ bind(l_overlap); // need to copy backwards } @@ -1248,6 +1247,7 @@ class StubGenerator: public StubCodeGenerator { } __ bind(l_4); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1269,15 +1269,9 @@ class StubGenerator: public StubCodeGenerator { Register tmp2 = R7_ARG5; Register tmp3 = R8_ARG6; -#if defined(ABI_ELFv2) address nooverlap_target = aligned ? - StubRoutines::arrayof_jbyte_disjoint_arraycopy() : - StubRoutines::jbyte_disjoint_arraycopy(); -#else - address nooverlap_target = aligned ? - ((FunctionDescriptor*)StubRoutines::arrayof_jbyte_disjoint_arraycopy())->entry() : - ((FunctionDescriptor*)StubRoutines::jbyte_disjoint_arraycopy())->entry(); -#endif + STUB_ENTRY(arrayof_jbyte_disjoint_arraycopy) : + STUB_ENTRY(jbyte_disjoint_arraycopy); array_overlap_test(nooverlap_target, 0); // Do reverse copy. We assume the case of actual overlap is rare enough @@ -1292,6 +1286,7 @@ class StubGenerator: public StubCodeGenerator { __ lbzx(tmp1, R3_ARG1, R5_ARG3); __ bge(CCR0, l_1); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1474,6 +1469,7 @@ class StubGenerator: public StubCodeGenerator { __ bdnz(l_5); } __ bind(l_4); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1495,15 +1491,9 @@ class StubGenerator: public StubCodeGenerator { Register tmp2 = R7_ARG5; Register tmp3 = R8_ARG6; -#if defined(ABI_ELFv2) address nooverlap_target = aligned ? - StubRoutines::arrayof_jshort_disjoint_arraycopy() : - StubRoutines::jshort_disjoint_arraycopy(); -#else - address nooverlap_target = aligned ? - ((FunctionDescriptor*)StubRoutines::arrayof_jshort_disjoint_arraycopy())->entry() : - ((FunctionDescriptor*)StubRoutines::jshort_disjoint_arraycopy())->entry(); -#endif + STUB_ENTRY(arrayof_jshort_disjoint_arraycopy) : + STUB_ENTRY(jshort_disjoint_arraycopy); array_overlap_test(nooverlap_target, 1); @@ -1517,6 +1507,7 @@ class StubGenerator: public StubCodeGenerator { __ lhzx(tmp2, R3_ARG1, tmp1); __ bge(CCR0, l_1); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1620,6 +1611,7 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", name); address start = __ function_entry(); generate_disjoint_int_copy_core(aligned); + __ li(R3_RET, 0); // return 0 __ blr(); return start; } @@ -1704,20 +1696,15 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", name); address start = __ function_entry(); -#if defined(ABI_ELFv2) address nooverlap_target = aligned ? - StubRoutines::arrayof_jint_disjoint_arraycopy() : - StubRoutines::jint_disjoint_arraycopy(); -#else - address nooverlap_target = aligned ? - ((FunctionDescriptor*)StubRoutines::arrayof_jint_disjoint_arraycopy())->entry() : - ((FunctionDescriptor*)StubRoutines::jint_disjoint_arraycopy())->entry(); -#endif + STUB_ENTRY(arrayof_jint_disjoint_arraycopy) : + STUB_ENTRY(jint_disjoint_arraycopy); array_overlap_test(nooverlap_target, 2); generate_conjoint_int_copy_core(aligned); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1796,6 +1783,7 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", name); address start = __ function_entry(); generate_disjoint_long_copy_core(aligned); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1878,19 +1866,14 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", name); address start = __ function_entry(); -#if defined(ABI_ELFv2) address nooverlap_target = aligned ? - StubRoutines::arrayof_jlong_disjoint_arraycopy() : - StubRoutines::jlong_disjoint_arraycopy(); -#else - address nooverlap_target = aligned ? - ((FunctionDescriptor*)StubRoutines::arrayof_jlong_disjoint_arraycopy())->entry() : - ((FunctionDescriptor*)StubRoutines::jlong_disjoint_arraycopy())->entry(); -#endif + STUB_ENTRY(arrayof_jlong_disjoint_arraycopy) : + STUB_ENTRY(jlong_disjoint_arraycopy); array_overlap_test(nooverlap_target, 3); generate_conjoint_long_copy_core(aligned); + __ li(R3_RET, 0); // return 0 __ blr(); return start; @@ -1910,15 +1893,9 @@ class StubGenerator: public StubCodeGenerator { address start = __ function_entry(); -#if defined(ABI_ELFv2) address nooverlap_target = aligned ? - StubRoutines::arrayof_oop_disjoint_arraycopy() : - StubRoutines::oop_disjoint_arraycopy(); -#else - address nooverlap_target = aligned ? - ((FunctionDescriptor*)StubRoutines::arrayof_oop_disjoint_arraycopy())->entry() : - ((FunctionDescriptor*)StubRoutines::oop_disjoint_arraycopy())->entry(); -#endif + STUB_ENTRY(arrayof_oop_disjoint_arraycopy) : + STUB_ENTRY(oop_disjoint_arraycopy); gen_write_ref_array_pre_barrier(R3_ARG1, R4_ARG2, R5_ARG3, dest_uninitialized, R9_ARG7); @@ -1934,7 +1911,9 @@ class StubGenerator: public StubCodeGenerator { generate_conjoint_long_copy_core(aligned); } - gen_write_ref_array_post_barrier(R9_ARG7, R10_ARG8, R11_scratch1, /*branchToEnd*/ false); + gen_write_ref_array_post_barrier(R9_ARG7, R10_ARG8, R11_scratch1); + __ li(R3_RET, 0); // return 0 + __ blr(); return start; } @@ -1964,11 +1943,460 @@ class StubGenerator: public StubCodeGenerator { generate_disjoint_long_copy_core(aligned); } - gen_write_ref_array_post_barrier(R9_ARG7, R10_ARG8, R11_scratch1, /*branchToEnd*/ false); + gen_write_ref_array_post_barrier(R9_ARG7, R10_ARG8, R11_scratch1); + __ li(R3_RET, 0); // return 0 + __ blr(); return start; } + + // Helper for generating a dynamic type check. + // Smashes only the given temp registers. + void generate_type_check(Register sub_klass, + Register super_check_offset, + Register super_klass, + Register temp, + Label& L_success) { + assert_different_registers(sub_klass, super_check_offset, super_klass); + + BLOCK_COMMENT("type_check:"); + + Label L_miss; + + __ check_klass_subtype_fast_path(sub_klass, super_klass, temp, R0, &L_success, &L_miss, NULL, + super_check_offset); + __ check_klass_subtype_slow_path(sub_klass, super_klass, temp, R0, &L_success, NULL); + + // Fall through on failure! + __ bind(L_miss); + } + + + // Generate stub for checked oop copy. + // + // Arguments for generated stub: + // from: R3 + // to: R4 + // count: R5 treated as signed + // ckoff: R6 (super_check_offset) + // ckval: R7 (super_klass) + // ret: R3 zero for success; (-1^K) where K is partial transfer count + // + address generate_checkcast_copy(const char *name, bool dest_uninitialized) { + + const Register R3_from = R3_ARG1; // source array address + const Register R4_to = R4_ARG2; // destination array address + const Register R5_count = R5_ARG3; // elements count + const Register R6_ckoff = R6_ARG4; // super_check_offset + const Register R7_ckval = R7_ARG5; // super_klass + + const Register R8_offset = R8_ARG6; // loop var, with stride wordSize + const Register R9_remain = R9_ARG7; // loop var, with stride -1 + const Register R10_oop = R10_ARG8; // actual oop copied + const Register R11_klass = R11_scratch1; // oop._klass + const Register R12_tmp = R12_scratch2; + + const Register R2_minus1 = R2; + + //__ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ function_entry(); + + // TODO: Assert that int is 64 bit sign extended and arrays are not conjoint. + + gen_write_ref_array_pre_barrier(R3_from, R4_to, R5_count, dest_uninitialized, R12_tmp, /* preserve: */ R6_ckoff, R7_ckval); + + //inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, R12_tmp, R3_RET); + + Label load_element, store_element, store_null, success, do_card_marks; + __ or_(R9_remain, R5_count, R5_count); // Initialize loop index, and test it. + __ li(R8_offset, 0); // Offset from start of arrays. + __ li(R2_minus1, -1); + __ bne(CCR0, load_element); + + // Empty array: Nothing to do. + __ li(R3_RET, 0); // Return 0 on (trivial) success. + __ blr(); + + // ======== begin loop ======== + // (Entry is load_element.) + __ align(OptoLoopAlignment); + __ bind(store_element); + if (UseCompressedOops) { + __ encode_heap_oop_not_null(R10_oop); + __ bind(store_null); + __ stw(R10_oop, R8_offset, R4_to); + } else { + __ bind(store_null); + __ std(R10_oop, R8_offset, R4_to); + } + + __ addi(R8_offset, R8_offset, heapOopSize); // Step to next offset. + __ add_(R9_remain, R2_minus1, R9_remain); // Decrement the count. + __ beq(CCR0, success); + + // ======== loop entry is here ======== + __ bind(load_element); + __ load_heap_oop(R10_oop, R8_offset, R3_from, &store_null); // Load the oop. + + __ load_klass(R11_klass, R10_oop); // Query the object klass. + + generate_type_check(R11_klass, R6_ckoff, R7_ckval, R12_tmp, + // Branch to this on success: + store_element); + // ======== end loop ======== + + // It was a real error; we must depend on the caller to finish the job. + // Register R9_remain has number of *remaining* oops, R5_count number of *total* oops. + // Emit GC store barriers for the oops we have copied (R5_count minus R9_remain), + // and report their number to the caller. + __ subf_(R5_count, R9_remain, R5_count); + __ nand(R3_RET, R5_count, R5_count); // report (-1^K) to caller + __ bne(CCR0, do_card_marks); + __ blr(); + + __ bind(success); + __ li(R3_RET, 0); + + __ bind(do_card_marks); + // Store check on R4_to[0..R5_count-1]. + gen_write_ref_array_post_barrier(R4_to, R5_count, R12_tmp, /* preserve: */ R3_RET); + __ blr(); + return start; + } + + + // Generate 'unsafe' array copy stub. + // Though just as safe as the other stubs, it takes an unscaled + // size_t argument instead of an element count. + // + // Arguments for generated stub: + // from: R3 + // to: R4 + // count: R5 byte count, treated as ssize_t, can be zero + // + // Examines the alignment of the operands and dispatches + // to a long, int, short, or byte copy loop. + // + address generate_unsafe_copy(const char* name, + address byte_copy_entry, + address short_copy_entry, + address int_copy_entry, + address long_copy_entry) { + + const Register R3_from = R3_ARG1; // source array address + const Register R4_to = R4_ARG2; // destination array address + const Register R5_count = R5_ARG3; // elements count (as long on PPC64) + + const Register R6_bits = R6_ARG4; // test copy of low bits + const Register R7_tmp = R7_ARG5; + + //__ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ function_entry(); + + // Bump this on entry, not on exit: + //inc_counter_np(SharedRuntime::_unsafe_array_copy_ctr, R6_bits, R7_tmp); + + Label short_copy, int_copy, long_copy; + + __ orr(R6_bits, R3_from, R4_to); + __ orr(R6_bits, R6_bits, R5_count); + __ andi_(R0, R6_bits, (BytesPerLong-1)); + __ beq(CCR0, long_copy); + + __ andi_(R0, R6_bits, (BytesPerInt-1)); + __ beq(CCR0, int_copy); + + __ andi_(R0, R6_bits, (BytesPerShort-1)); + __ beq(CCR0, short_copy); + + // byte_copy: + __ b(byte_copy_entry); + + __ bind(short_copy); + __ srwi(R5_count, R5_count, LogBytesPerShort); + __ b(short_copy_entry); + + __ bind(int_copy); + __ srwi(R5_count, R5_count, LogBytesPerInt); + __ b(int_copy_entry); + + __ bind(long_copy); + __ srwi(R5_count, R5_count, LogBytesPerLong); + __ b(long_copy_entry); + + return start; + } + + + // Perform range checks on the proposed arraycopy. + // Kills the two temps, but nothing else. + // Also, clean the sign bits of src_pos and dst_pos. + void arraycopy_range_checks(Register src, // source array oop + Register src_pos, // source position + Register dst, // destination array oop + Register dst_pos, // destination position + Register length, // length of copy + Register temp1, Register temp2, + Label& L_failed) { + BLOCK_COMMENT("arraycopy_range_checks:"); + + const Register array_length = temp1; // scratch + const Register end_pos = temp2; // scratch + + // if (src_pos + length > arrayOop(src)->length() ) FAIL; + __ lwa(array_length, arrayOopDesc::length_offset_in_bytes(), src); + __ add(end_pos, src_pos, length); // src_pos + length + __ cmpd(CCR0, end_pos, array_length); + __ bgt(CCR0, L_failed); + + // if (dst_pos + length > arrayOop(dst)->length() ) FAIL; + __ lwa(array_length, arrayOopDesc::length_offset_in_bytes(), dst); + __ add(end_pos, dst_pos, length); // src_pos + length + __ cmpd(CCR0, end_pos, array_length); + __ bgt(CCR0, L_failed); + + BLOCK_COMMENT("arraycopy_range_checks done"); + } + + + // + // Generate generic array copy stubs + // + // Input: + // R3 - src oop + // R4 - src_pos + // R5 - dst oop + // R6 - dst_pos + // R7 - element count + // + // Output: + // R3 == 0 - success + // R3 == -1 - need to call System.arraycopy + // + address generate_generic_copy(const char *name, + address entry_jbyte_arraycopy, + address entry_jshort_arraycopy, + address entry_jint_arraycopy, + address entry_oop_arraycopy, + address entry_disjoint_oop_arraycopy, + address entry_jlong_arraycopy, + address entry_checkcast_arraycopy) { + Label L_failed, L_objArray; + + // Input registers + const Register src = R3_ARG1; // source array oop + const Register src_pos = R4_ARG2; // source position + const Register dst = R5_ARG3; // destination array oop + const Register dst_pos = R6_ARG4; // destination position + const Register length = R7_ARG5; // elements count + + // registers used as temp + const Register src_klass = R8_ARG6; // source array klass + const Register dst_klass = R9_ARG7; // destination array klass + const Register lh = R10_ARG8; // layout handler + const Register temp = R2; + + //__ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ function_entry(); + + // Bump this on entry, not on exit: + //inc_counter_np(SharedRuntime::_generic_array_copy_ctr, lh, temp); + + // In principle, the int arguments could be dirty. + + //----------------------------------------------------------------------- + // Assembler stubs will be used for this call to arraycopy + // if the following conditions are met: + // + // (1) src and dst must not be null. + // (2) src_pos must not be negative. + // (3) dst_pos must not be negative. + // (4) length must not be negative. + // (5) src klass and dst klass should be the same and not NULL. + // (6) src and dst should be arrays. + // (7) src_pos + length must not exceed length of src. + // (8) dst_pos + length must not exceed length of dst. + BLOCK_COMMENT("arraycopy initial argument checks"); + + __ cmpdi(CCR1, src, 0); // if (src == NULL) return -1; + __ extsw_(src_pos, src_pos); // if (src_pos < 0) return -1; + __ cmpdi(CCR5, dst, 0); // if (dst == NULL) return -1; + __ cror(CCR1, Assembler::equal, CCR0, Assembler::less); + __ extsw_(dst_pos, dst_pos); // if (src_pos < 0) return -1; + __ cror(CCR5, Assembler::equal, CCR0, Assembler::less); + __ extsw_(length, length); // if (length < 0) return -1; + __ cror(CCR1, Assembler::equal, CCR5, Assembler::equal); + __ cror(CCR1, Assembler::equal, CCR0, Assembler::less); + __ beq(CCR1, L_failed); + + BLOCK_COMMENT("arraycopy argument klass checks"); + __ load_klass(src_klass, src); + __ load_klass(dst_klass, dst); + + // Load layout helper + // + // |array_tag| | header_size | element_type | |log2_element_size| + // 32 30 24 16 8 2 0 + // + // array_tag: typeArray = 0x3, objArray = 0x2, non-array = 0x0 + // + + int lh_offset = in_bytes(Klass::layout_helper_offset()); + + // Load 32-bits signed value. Use br() instruction with it to check icc. + __ lwz(lh, lh_offset, src_klass); + + // Handle objArrays completely differently... + jint objArray_lh = Klass::array_layout_helper(T_OBJECT); + __ load_const_optimized(temp, objArray_lh, R0); + __ cmpw(CCR0, lh, temp); + __ beq(CCR0, L_objArray); + + __ cmpd(CCR5, src_klass, dst_klass); // if (src->klass() != dst->klass()) return -1; + __ cmpwi(CCR6, lh, Klass::_lh_neutral_value); // if (!src->is_Array()) return -1; + + __ crnand(CCR5, Assembler::equal, CCR6, Assembler::less); + __ beq(CCR5, L_failed); + + // At this point, it is known to be a typeArray (array_tag 0x3). +#ifdef ASSERT + { Label L; + jint lh_prim_tag_in_place = (Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift); + __ load_const_optimized(temp, lh_prim_tag_in_place, R0); + __ cmpw(CCR0, lh, temp); + __ bge(CCR0, L); + __ stop("must be a primitive array"); + __ bind(L); + } +#endif + + arraycopy_range_checks(src, src_pos, dst, dst_pos, length, + temp, dst_klass, L_failed); + + // TypeArrayKlass + // + // src_addr = (src + array_header_in_bytes()) + (src_pos << log2elemsize); + // dst_addr = (dst + array_header_in_bytes()) + (dst_pos << log2elemsize); + // + + const Register offset = dst_klass; // array offset + const Register elsize = src_klass; // log2 element size + + __ rldicl(offset, lh, 64 - Klass::_lh_header_size_shift, 64 - exact_log2(Klass::_lh_header_size_mask + 1)); + __ andi(elsize, lh, Klass::_lh_log2_element_size_mask); + __ add(src, offset, src); // src array offset + __ add(dst, offset, dst); // dst array offset + + // Next registers should be set before the jump to corresponding stub. + const Register from = R3_ARG1; // source array address + const Register to = R4_ARG2; // destination array address + const Register count = R5_ARG3; // elements count + + // 'from', 'to', 'count' registers should be set in this order + // since they are the same as 'src', 'src_pos', 'dst'. + + BLOCK_COMMENT("scale indexes to element size"); + __ sld(src_pos, src_pos, elsize); + __ sld(dst_pos, dst_pos, elsize); + __ add(from, src_pos, src); // src_addr + __ add(to, dst_pos, dst); // dst_addr + __ mr(count, length); // length + + BLOCK_COMMENT("choose copy loop based on element size"); + // Using conditional branches with range 32kB. + const int bo = Assembler::bcondCRbiIs1, bi = Assembler::bi0(CCR0, Assembler::equal); + __ cmpwi(CCR0, elsize, 0); + __ bc(bo, bi, entry_jbyte_arraycopy); + __ cmpwi(CCR0, elsize, LogBytesPerShort); + __ bc(bo, bi, entry_jshort_arraycopy); + __ cmpwi(CCR0, elsize, LogBytesPerInt); + __ bc(bo, bi, entry_jint_arraycopy); +#ifdef ASSERT + { Label L; + __ cmpwi(CCR0, elsize, LogBytesPerLong); + __ beq(CCR0, L); + __ stop("must be long copy, but elsize is wrong"); + __ bind(L); + } +#endif + __ b(entry_jlong_arraycopy); + + // ObjArrayKlass + __ bind(L_objArray); + // live at this point: src_klass, dst_klass, src[_pos], dst[_pos], length + + Label L_disjoint_plain_copy, L_checkcast_copy; + // test array classes for subtyping + __ cmpd(CCR0, src_klass, dst_klass); // usual case is exact equality + __ bne(CCR0, L_checkcast_copy); + + // Identically typed arrays can be copied without element-wise checks. + arraycopy_range_checks(src, src_pos, dst, dst_pos, length, + temp, lh, L_failed); + + __ addi(src, src, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //src offset + __ addi(dst, dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //dst offset + __ sldi(src_pos, src_pos, LogBytesPerHeapOop); + __ sldi(dst_pos, dst_pos, LogBytesPerHeapOop); + __ add(from, src_pos, src); // src_addr + __ add(to, dst_pos, dst); // dst_addr + __ mr(count, length); // length + __ b(entry_oop_arraycopy); + + __ bind(L_checkcast_copy); + // live at this point: src_klass, dst_klass + { + // Before looking at dst.length, make sure dst is also an objArray. + __ lwz(temp, lh_offset, dst_klass); + __ cmpw(CCR0, lh, temp); + __ bne(CCR0, L_failed); + + // It is safe to examine both src.length and dst.length. + arraycopy_range_checks(src, src_pos, dst, dst_pos, length, + temp, lh, L_failed); + + // Marshal the base address arguments now, freeing registers. + __ addi(src, src, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //src offset + __ addi(dst, dst, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); //dst offset + __ sldi(src_pos, src_pos, LogBytesPerHeapOop); + __ sldi(dst_pos, dst_pos, LogBytesPerHeapOop); + __ add(from, src_pos, src); // src_addr + __ add(to, dst_pos, dst); // dst_addr + __ mr(count, length); // length + + Register sco_temp = R6_ARG4; // This register is free now. + assert_different_registers(from, to, count, sco_temp, + dst_klass, src_klass); + + // Generate the type check. + int sco_offset = in_bytes(Klass::super_check_offset_offset()); + __ lwz(sco_temp, sco_offset, dst_klass); + generate_type_check(src_klass, sco_temp, dst_klass, + temp, L_disjoint_plain_copy); + + // Fetch destination element klass from the ObjArrayKlass header. + int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); + + // The checkcast_copy loop needs two extra arguments: + __ ld(R7_ARG5, ek_offset, dst_klass); // dest elem klass + __ lwz(R6_ARG4, sco_offset, R7_ARG5); // sco of elem klass + __ b(entry_checkcast_arraycopy); + } + + __ bind(L_disjoint_plain_copy); + __ b(entry_disjoint_oop_arraycopy); + + __ bind(L_failed); + __ li(R3_RET, -1); // return -1 + __ blr(); + return start; + } + + void generate_arraycopy_stubs() { // Note: the disjoint stubs must be generated first, some of // the conjoint stubs use them. @@ -2005,6 +2433,24 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_arrayof_oop_arraycopy = generate_conjoint_oop_copy(true, "arrayof_oop_arraycopy", false); StubRoutines::_arrayof_oop_arraycopy_uninit = generate_conjoint_oop_copy(true, "arrayof_oop_arraycopy", true); + // special/generic versions + StubRoutines::_checkcast_arraycopy = generate_checkcast_copy("checkcast_arraycopy", false); + StubRoutines::_checkcast_arraycopy_uninit = generate_checkcast_copy("checkcast_arraycopy_uninit", true); + + StubRoutines::_unsafe_arraycopy = generate_unsafe_copy("unsafe_arraycopy", + STUB_ENTRY(jbyte_arraycopy), + STUB_ENTRY(jshort_arraycopy), + STUB_ENTRY(jint_arraycopy), + STUB_ENTRY(jlong_arraycopy)); + StubRoutines::_generic_arraycopy = generate_generic_copy("generic_arraycopy", + STUB_ENTRY(jbyte_arraycopy), + STUB_ENTRY(jshort_arraycopy), + STUB_ENTRY(jint_arraycopy), + STUB_ENTRY(oop_arraycopy), + STUB_ENTRY(oop_disjoint_arraycopy), + STUB_ENTRY(jlong_arraycopy), + STUB_ENTRY(checkcast_arraycopy)); + // fill routines StubRoutines::_jbyte_fill = generate_fill(T_BYTE, false, "jbyte_fill"); StubRoutines::_jshort_fill = generate_fill(T_SHORT, false, "jshort_fill"); diff --git a/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp index 65239dd317d..1f49fe1de26 100644 --- a/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/stubRoutines_ppc_64.cpp @@ -34,7 +34,7 @@ // CRC32 Intrinsics. void StubRoutines::ppc64::generate_load_crc_table_addr(MacroAssembler* masm, Register table) { - __ load_const(table, StubRoutines::_crc_table_adr); + __ load_const_optimized(table, StubRoutines::_crc_table_adr, R0); } // CRC32 Intrinsics. diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp index 361e637d253..4691f70f8eb 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.cpp @@ -255,34 +255,33 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* if (TieredCompilation) { const int increment = InvocationCounter::count_increment; - const int mask = ((1 << Tier0InvokeNotifyFreqLog) - 1) << InvocationCounter::count_shift; Label no_mdo; if (ProfileInterpreter) { - const Register Rmdo = Rscratch1; + const Register Rmdo = R3_counters; // If no method data exists, go to profile_continue. __ ld(Rmdo, in_bytes(Method::method_data_offset()), R19_method); __ cmpdi(CCR0, Rmdo, 0); __ beq(CCR0, no_mdo); // Increment backedge counter in the MDO. - const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); - __ lwz(Rscratch2, mdo_bc_offs, Rmdo); + const int mdo_ic_offs = in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + __ lwz(Rscratch2, mdo_ic_offs, Rmdo); + __ lwz(Rscratch1, in_bytes(MethodData::invoke_mask_offset()), Rmdo); __ addi(Rscratch2, Rscratch2, increment); - __ stw(Rscratch2, mdo_bc_offs, Rmdo); - __ load_const_optimized(Rscratch1, mask, R0); + __ stw(Rscratch2, mdo_ic_offs, Rmdo); __ and_(Rscratch1, Rscratch2, Rscratch1); __ bne(CCR0, done); __ b(*overflow); } // Increment counter in MethodCounters*. - const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); + const int mo_bc_offs = in_bytes(MethodCounters::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); __ bind(no_mdo); __ get_method_counters(R19_method, R3_counters, done); __ lwz(Rscratch2, mo_bc_offs, R3_counters); + __ lwz(Rscratch1, in_bytes(MethodCounters::invoke_mask_offset()), R3_counters); __ addi(Rscratch2, Rscratch2, increment); __ stw(Rscratch2, mo_bc_offs, R3_counters); - __ load_const_optimized(Rscratch1, mask, R0); __ and_(Rscratch1, Rscratch2, Rscratch1); __ beq(CCR0, *overflow); @@ -303,8 +302,7 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* // Check if we must create a method data obj. if (ProfileInterpreter && profile_method != NULL) { const Register profile_limit = Rscratch1; - int pl_offs = __ load_const_optimized(profile_limit, &InvocationCounter::InterpreterProfileLimit, R0, true); - __ lwz(profile_limit, pl_offs, profile_limit); + __ lwz(profile_limit, in_bytes(MethodCounters::interpreter_profile_limit_offset()), R3_counters); // Test to see if we should create a method data oop. __ cmpw(CCR0, Rsum_ivc_bec, profile_limit); __ blt(CCR0, *profile_method_continue); @@ -314,9 +312,7 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow, Label* // Finally check for counter overflow. if (overflow) { const Register invocation_limit = Rscratch1; - int il_offs = __ load_const_optimized(invocation_limit, &InvocationCounter::InterpreterInvocationLimit, R0, true); - __ lwz(invocation_limit, il_offs, invocation_limit); - assert(4 == sizeof(InvocationCounter::InterpreterInvocationLimit), "unexpected field size"); + __ lwz(invocation_limit, in_bytes(MethodCounters::interpreter_invocation_limit_offset()), R3_counters); __ cmpw(CCR0, Rsum_ivc_bec, invocation_limit); __ bge(CCR0, *overflow); } @@ -1484,9 +1480,9 @@ void AbstractInterpreter::layout_activation(Method* method, intptr_t* locals_base = (caller->is_interpreted_frame()) ? caller->interpreter_frame_esp() + caller_actual_parameters : - caller->sp() + method->max_locals() - 1 + (frame::abi_minframe_size / Interpreter::stackElementSize) ; + caller->sp() + method->max_locals() - 1 + (frame::abi_minframe_size / Interpreter::stackElementSize); - intptr_t* monitor_base = caller->sp() - frame::ijava_state_size / Interpreter::stackElementSize ; + intptr_t* monitor_base = caller->sp() - frame::ijava_state_size / Interpreter::stackElementSize; intptr_t* monitor = monitor_base - (moncount * frame::interpreter_frame_monitor_size()); intptr_t* esp_base = monitor - 1; intptr_t* esp = esp_base - tempcount - popframe_extra_args; diff --git a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp index 4450dd71897..c08e6d44cf7 100644 --- a/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/templateInterpreter_ppc.hpp @@ -37,5 +37,3 @@ const static int InterpreterCodeSize = 230*K; #endif // CPU_PPC_VM_TEMPLATEINTERPRETER_PPC_HPP - - diff --git a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp index 0660726181c..4a1c44a4ce3 100644 --- a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp @@ -1626,12 +1626,13 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // -------------------------------------------------------------------------- // Normal (non-jsr) branch handling + // Bump bytecode pointer by displacement (take the branch). + __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr. + const bool increment_invocation_counter_for_backward_branches = UseCompiler && UseLoopCounter; if (increment_invocation_counter_for_backward_branches) { - //__ unimplemented("branch invocation counter"); - Label Lforward; - __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr. + __ dispatch_prolog(vtos); // Check branch direction. __ cmpdi(CCR0, Rdisp, 0); @@ -1642,7 +1643,6 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (TieredCompilation) { Label Lno_mdo, Loverflow; const int increment = InvocationCounter::count_increment; - const int mask = ((1 << Tier0BackedgeNotifyFreqLog) - 1) << InvocationCounter::count_shift; if (ProfileInterpreter) { Register Rmdo = Rscratch1; @@ -1654,7 +1654,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Increment backedge counter in the MDO. const int mdo_bc_offs = in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); __ lwz(Rscratch2, mdo_bc_offs, Rmdo); - __ load_const_optimized(Rscratch3, mask, R0); + __ lwz(Rscratch3, in_bytes(MethodData::backedge_mask_offset()), Rmdo); __ addi(Rscratch2, Rscratch2, increment); __ stw(Rscratch2, mdo_bc_offs, Rmdo); __ and_(Rscratch3, Rscratch2, Rscratch3); @@ -1666,19 +1666,19 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { const int mo_bc_offs = in_bytes(MethodCounters::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset()); __ bind(Lno_mdo); __ lwz(Rscratch2, mo_bc_offs, R4_counters); - __ load_const_optimized(Rscratch3, mask, R0); + __ lwz(Rscratch3, in_bytes(MethodCounters::backedge_mask_offset()), R4_counters); __ addi(Rscratch2, Rscratch2, increment); - __ stw(Rscratch2, mo_bc_offs, R19_method); + __ stw(Rscratch2, mo_bc_offs, R4_counters); __ and_(Rscratch3, Rscratch2, Rscratch3); __ bne(CCR0, Lforward); __ bind(Loverflow); // Notify point for loop, pass branch bytecode. - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R14_bcp, true); + __ subf(R4_ARG2, Rdisp, R14_bcp); // Compute branch bytecode (previous bcp). + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), R4_ARG2, true); // Was an OSR adapter generated? - // O0 = osr nmethod __ cmpdi(CCR0, R3_RET, 0); __ beq(CCR0, Lforward); @@ -1714,27 +1714,23 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ increment_backedge_counter(R4_counters, invoke_ctr, Rscratch2, Rscratch3); if (ProfileInterpreter) { - __ test_invocation_counter_for_mdp(invoke_ctr, Rscratch2, Lforward); + __ test_invocation_counter_for_mdp(invoke_ctr, R4_counters, Rscratch2, Lforward); if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(bumped_count, R14_bcp, Rscratch2); + __ test_backedge_count_for_osr(bumped_count, R4_counters, R14_bcp, Rdisp, Rscratch2); } } else { if (UseOnStackReplacement) { - __ test_backedge_count_for_osr(invoke_ctr, R14_bcp, Rscratch2); + __ test_backedge_count_for_osr(invoke_ctr, R4_counters, R14_bcp, Rdisp, Rscratch2); } } } __ bind(Lforward); + __ dispatch_epilog(vtos); } else { - // Bump bytecode pointer by displacement (take the branch). - __ add(R14_bcp, Rdisp, R14_bcp); // Add to bc addr. + __ dispatch_next(vtos); } - // Continue with bytecode @ target. - // %%%%% Like Intel, could speed things up by moving bytecode fetch to code above, - // %%%%% and changing dispatch_next to dispatch_only. - __ dispatch_next(vtos); } // Helper function for if_cmp* methods below. diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index 90bd9c2ad7a..774d90b5cf1 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -38,7 +38,6 @@ # include int VM_Version::_features = VM_Version::unknown_m; -int VM_Version::_measured_cache_line_size = 32; // pessimistic init value const char* VM_Version::_features_str = ""; bool VM_Version::_is_determine_features_test_running = false; @@ -56,7 +55,7 @@ void VM_Version::initialize() { // If PowerArchitecturePPC64 hasn't been specified explicitly determine from features. if (FLAG_IS_DEFAULT(PowerArchitecturePPC64)) { - if (VM_Version::has_lqarx()) { + if (VM_Version::has_tcheck() && VM_Version::has_lqarx()) { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 8); } else if (VM_Version::has_popcntw()) { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 7); @@ -68,10 +67,19 @@ void VM_Version::initialize() { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 0); } } - guarantee(PowerArchitecturePPC64 == 0 || PowerArchitecturePPC64 == 5 || - PowerArchitecturePPC64 == 6 || PowerArchitecturePPC64 == 7 || - PowerArchitecturePPC64 == 8, - "PowerArchitecturePPC64 should be 0, 5, 6, 7, or 8"); + + bool PowerArchitecturePPC64_ok = false; + switch (PowerArchitecturePPC64) { + case 8: if (!VM_Version::has_tcheck() ) break; + 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; + case 0: PowerArchitecturePPC64_ok = true; break; + default: break; + } + guarantee(PowerArchitecturePPC64_ok, "PowerArchitecturePPC64 cannot be set to " + UINTX_FORMAT " on this machine", PowerArchitecturePPC64); // Power 8: Configure Data Stream Control Register. if (PowerArchitecturePPC64 >= 8) { @@ -132,9 +140,15 @@ void VM_Version::initialize() { // and 'atomic long memory ops' (see Unsafe_GetLongVolatile). _supports_cx8 = true; + // Used by C1. + _supports_atomic_getset4 = true; + _supports_atomic_getadd4 = true; + _supports_atomic_getset8 = true; + _supports_atomic_getadd8 = true; + UseSSE = 0; // Only on x86 and x64 - intx cache_line_size = _measured_cache_line_size; + intx cache_line_size = L1_data_cache_line_size(); if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) AllocatePrefetchStyle = 1; @@ -261,11 +275,9 @@ void VM_Version::initialize() { } } - // This machine does not allow unaligned memory accesses - if (UseUnalignedAccesses) { - if (!FLAG_IS_DEFAULT(UseUnalignedAccesses)) - warning("Unaligned memory access is not available on this CPU"); - FLAG_SET_DEFAULT(UseUnalignedAccesses, false); + // This machine allows unaligned memory accesses + if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) { + FLAG_SET_DEFAULT(UseUnalignedAccesses, true); } } @@ -291,7 +303,7 @@ bool VM_Version::use_biased_locking() { } void VM_Version::print_features() { - tty->print_cr("Version: %s cache_line_size = %d", cpu_features(), (int) get_cache_line_size()); + tty->print_cr("Version: %s L1_data_cache_line_size=%d", cpu_features(), L1_data_cache_line_size()); } #ifdef COMPILER2 @@ -592,7 +604,7 @@ void VM_Version::determine_features() { int count = 0; // count zeroed bytes for (int i = 0; i < BUFFER_SIZE; i++) if (test_area[i] == 0) count++; guarantee(is_power_of_2(count), "cache line size needs to be a power of 2"); - _measured_cache_line_size = count; + _L1_data_cache_line_size = count; // Execute code. Illegal instructions will be replaced by 0 in the signal handler. VM_Version::_is_determine_features_test_running = true; diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp index 6fc76e4cd41..d5f6dc6cc81 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp @@ -65,7 +65,6 @@ protected: all_features_m = -1 }; static int _features; - static int _measured_cache_line_size; static const char* _features_str; static bool _is_determine_features_test_running; @@ -99,8 +98,6 @@ public: static const char* cpu_features() { return _features_str; } - static int get_cache_line_size() { return _measured_cache_line_size; } - // Assembler testing static void allow_all(); static void revert(); diff --git a/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp b/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp index 0165fb22e34..d19c211300f 100644 --- a/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp +++ b/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp @@ -76,7 +76,8 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { // We might implicit NULL fault here. address npe_addr = __ pc(); // npe = null pointer exception - __ load_klass_with_trap_null_check(rcvr_klass, R3); + __ null_check(R3, oopDesc::klass_offset_in_bytes(), /*implicit only*/NULL); + __ load_klass(rcvr_klass, R3); // Set method (in case of interpreted method), and destination address. int entry_offset = InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size(); @@ -111,8 +112,8 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { // If the vtable entry is null, the method is abstract. address ame_addr = __ pc(); // ame = abstract method error - - __ load_with_trap_null_check(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); + __ null_check(R19_method, in_bytes(Method::from_compiled_offset()), /*implicit only*/NULL); + __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); __ mtctr(R12_scratch2); __ bctr(); masm->flush(); @@ -158,7 +159,8 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { // We might implicit NULL fault here. address npe_addr = __ pc(); // npe = null pointer exception - __ load_klass_with_trap_null_check(rcvr_klass, R3_ARG1); + __ null_check(R3_ARG1, oopDesc::klass_offset_in_bytes(), /*implicit only*/NULL); + __ load_klass(rcvr_klass, R3_ARG1); BLOCK_COMMENT("Load start of itable entries into itable_entry."); __ lwz(vtable_len, InstanceKlass::vtable_length_offset() * wordSize, rcvr_klass); @@ -217,15 +219,7 @@ VtableStub* VtableStubs::create_itable_stub(int vtable_index) { address ame_addr = __ pc(); // ame = abstract method error // Must do an explicit check if implicit checks are disabled. - assert(!MacroAssembler::needs_explicit_null_check(in_bytes(Method::from_compiled_offset())), "sanity"); - if (!ImplicitNullChecks || !os::zero_page_read_protected()) { - if (TrapBasedNullChecks) { - __ trap_null_check(R19_method); - } else { - __ cmpdi(CCR0, R19_method, 0); - __ beq(CCR0, throw_icce); - } - } + __ null_check(R19_method, in_bytes(Method::from_compiled_offset()), &throw_icce); __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); __ mtctr(R12_scratch2); __ bctr(); diff --git a/hotspot/src/os/aix/vm/c1_globals_aix.hpp b/hotspot/src/os/aix/vm/c1_globals_aix.hpp new file mode 100644 index 00000000000..45b57f71954 --- /dev/null +++ b/hotspot/src/os/aix/vm/c1_globals_aix.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright 2012, 2015 SAP AG. All rights reserved. + * 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 OS_AIX_VM_C1_GLOBALS_AIX_HPP +#define OS_AIX_VM_C1_GLOBALS_AIX_HPP + +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +// +// Sets the default values for operating system dependent flags used by the +// client compiler. (see c1_globals.hpp) +// + +#endif // OS_AIX_VM_C1_GLOBALS_AIX_HPP From d60a09e9c5c58cb7c32e362b778008c625b16ab1 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 4 Dec 2015 23:46:19 +0300 Subject: [PATCH 025/215] 8072008: Emit direct call instead of linkTo* for recursive indy/MH.invoke* calls Reviewed-by: jrose, dlong, aph, forax --- hotspot/src/cpu/aarch64/vm/aarch64.ad | 20 +- .../cpu/aarch64/vm/macroAssembler_aarch64.cpp | 4 +- .../cpu/aarch64/vm/macroAssembler_aarch64.hpp | 2 +- hotspot/src/cpu/ppc/vm/ppc.ad | 10 +- hotspot/src/cpu/sparc/vm/assembler_sparc.hpp | 2 + .../cpu/sparc/vm/assembler_sparc.inline.hpp | 2 + .../src/cpu/sparc/vm/macroAssembler_sparc.cpp | 5 +- .../src/cpu/sparc/vm/macroAssembler_sparc.hpp | 6 +- .../sparc/vm/macroAssembler_sparc.inline.hpp | 10 +- hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp | 5 +- hotspot/src/cpu/sparc/vm/sparc.ad | 34 +-- hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp | 4 +- hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp | 2 +- hotspot/src/cpu/x86/vm/x86_32.ad | 19 +- hotspot/src/cpu/x86/vm/x86_64.ad | 21 +- hotspot/src/share/vm/asm/codeBuffer.cpp | 25 ++ hotspot/src/share/vm/asm/codeBuffer.hpp | 5 +- hotspot/src/share/vm/ci/ciMethod.hpp | 6 + hotspot/src/share/vm/classfile/vmSymbols.hpp | 5 + hotspot/src/share/vm/code/compiledIC.cpp | 2 +- hotspot/src/share/vm/code/nmethod.cpp | 84 ++++++- hotspot/src/share/vm/code/nmethod.hpp | 11 +- hotspot/src/share/vm/code/relocInfo.cpp | 61 ++++- hotspot/src/share/vm/code/relocInfo.hpp | 54 +++-- .../src/share/vm/interpreter/linkResolver.cpp | 27 +++ .../src/share/vm/interpreter/linkResolver.hpp | 6 + hotspot/src/share/vm/opto/callGenerator.cpp | 38 ++- hotspot/src/share/vm/opto/callGenerator.hpp | 5 +- hotspot/src/share/vm/opto/callnode.cpp | 3 +- hotspot/src/share/vm/opto/callnode.hpp | 20 +- hotspot/src/share/vm/opto/doCall.cpp | 96 ++++++++ hotspot/src/share/vm/opto/library_call.cpp | 14 ++ hotspot/src/share/vm/opto/machnode.cpp | 3 +- hotspot/src/share/vm/opto/machnode.hpp | 22 +- hotspot/src/share/vm/opto/matcher.cpp | 1 + hotspot/src/share/vm/prims/methodHandles.cpp | 13 ++ hotspot/src/share/vm/prims/methodHandles.hpp | 6 + hotspot/src/share/vm/prims/whitebox.cpp | 6 + .../src/share/vm/runtime/sharedRuntime.cpp | 90 ++++++-- .../src/share/vm/runtime/sharedRuntime.hpp | 2 + .../src/share/vm/runtime/vm_operations.hpp | 9 + .../compiler/jsr292/NonInlinedCall/Agent.java | 48 ++++ .../jsr292/NonInlinedCall/GCTest.java | 105 +++++++++ .../jsr292/NonInlinedCall/InvokeTest.java | 218 ++++++++++++++++++ .../NonInlinedCall/NonInlinedReinvoker.java | 48 ++++ .../jsr292/NonInlinedCall/RedefineTest.java | 157 +++++++++++++ .../sanity/MismatchedWhiteBox/WhiteBox.java | 2 +- 47 files changed, 1190 insertions(+), 148 deletions(-) create mode 100644 hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java create mode 100644 hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java create mode 100644 hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java create mode 100644 hotspot/test/compiler/jsr292/NonInlinedCall/NonInlinedReinvoker.java create mode 100644 hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index afa30b74491..75b598e902c 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -4667,17 +4667,12 @@ encode %{ if (!_method) { // A call to a runtime wrapper, e.g. new, new_typeArray_Java, uncommon_trap. call = __ trampoline_call(Address(addr, relocInfo::runtime_call_type), &cbuf); - } else if (_optimized_virtual) { - call = __ trampoline_call(Address(addr, relocInfo::opt_virtual_call_type), &cbuf); } else { - call = __ trampoline_call(Address(addr, relocInfo::static_call_type), &cbuf); - } - if (call == NULL) { - ciEnv::current()->record_failure("CodeCache is full"); - return; - } + int method_index = resolved_method_index(cbuf); + RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) + : static_call_Relocation::spec(method_index); + call = __ trampoline_call(Address(addr, rspec), &cbuf); - if (_method) { // Emit stub for static call address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); if (stub == NULL) { @@ -4685,11 +4680,16 @@ encode %{ return; } } + if (call == NULL) { + ciEnv::current()->record_failure("CodeCache is full"); + return; + } %} enc_class aarch64_enc_java_dynamic_call(method meth) %{ MacroAssembler _masm(&cbuf); - address call = __ ic_call((address)$meth$$method); + int method_index = resolved_method_index(cbuf); + address call = __ ic_call((address)$meth$$method, method_index); if (call == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index c9608bc7492..8fed72e1313 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -732,8 +732,8 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset, return stub; } -address MacroAssembler::ic_call(address entry) { - RelocationHolder rh = virtual_call_Relocation::spec(pc()); +address MacroAssembler::ic_call(address entry, jint method_index) { + RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); // address const_ptr = long_constant((jlong)Universe::non_oop_word()); // unsigned long offset; // ldr_constant(rscratch2, const_ptr); diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp index 4c4e79b8629..54c608fada0 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp @@ -983,7 +983,7 @@ public: } // Emit the CompiledIC call idiom - address ic_call(address entry); + address ic_call(address entry, jint method_index = 0); public: diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index aefdf28133f..615f74eecf9 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -3396,11 +3396,13 @@ encode %{ } const int entry_point_toc_offset = __ offset_to_method_toc(entry_point_toc_addr); + // Emit the trampoline stub which will be related to the branch-and-link below. CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); if (ciEnv::current()->failing()) { return; } // Code cache may be full. - __ relocate(_optimized_virtual ? - relocInfo::opt_virtual_call_type : relocInfo::static_call_type); + int method_index = resolved_method_index(cbuf); + __ relocate(_optimized_virtual ? opt_virtual_call_Relocate::spec(method_index) + : static_call_Relocate::spec(method_index)); } // The real call. @@ -3450,8 +3452,8 @@ encode %{ const address virtual_call_oop_addr = __ addr_at(virtual_call_oop_addr_offset); assert(MacroAssembler::is_load_const_from_method_toc_at(virtual_call_oop_addr), "should be load from TOC"); - - __ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr)); + int method_index = resolved_method_index(cbuf); + __ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr, method_index)); } // At this point I do not have the address of the trampoline stub, diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp index e2ef96c727c..7c9c86a1466 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp @@ -816,6 +816,8 @@ public: inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type ); inline void call( Label& L, relocInfo::relocType rt = relocInfo::runtime_call_type ); + inline void call( address d, RelocationHolder const& rspec ); + public: // pp 150 diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp index 2bbf95e3b61..197e26fa6f8 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp @@ -76,6 +76,8 @@ inline void Assembler::cbcond(Condition c, CC cc, Register s1, int simm5, Label& inline void Assembler::call( address d, relocInfo::relocType rt ) { insert_nop_after_cbcond(); cti(); emit_data( op(call_op) | wdisp(intptr_t(d), intptr_t(pc()), 30), rt); has_delay_slot(); assert(rt != relocInfo::virtual_call_type, "must use virtual_call_Relocation::spec"); } inline void Assembler::call( Label& L, relocInfo::relocType rt ) { insert_nop_after_cbcond(); call( target(L), rt); } +inline void Assembler::call( address d, RelocationHolder const& rspec ) { insert_nop_after_cbcond(); cti(); emit_data( op(call_op) | wdisp(intptr_t(d), intptr_t(pc()), 30), rspec); has_delay_slot(); assert(rspec.type() != relocInfo::virtual_call_type, "must use virtual_call_Relocation::spec"); } + inline void Assembler::flush( Register s1, Register s2) { emit_int32( op(arith_op) | op3(flush_op3) | rs1(s1) | rs2(s2)); } inline void Assembler::flush( Register s1, int simm13a) { emit_data( op(arith_op) | op3(flush_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp index 59b5b41a0d8..0c4fc97cc6b 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp @@ -770,8 +770,8 @@ void MacroAssembler::set_vm_result(Register oop_result) { } -void MacroAssembler::ic_call(address entry, bool emit_delay) { - RelocationHolder rspec = virtual_call_Relocation::spec(pc()); +void MacroAssembler::ic_call(address entry, bool emit_delay, jint method_index) { + RelocationHolder rspec = virtual_call_Relocation::spec(pc(), method_index); patchable_set((intptr_t)Universe::non_oop_word(), G5_inline_cache_reg); relocate(rspec); call(entry, relocInfo::none); @@ -780,7 +780,6 @@ void MacroAssembler::ic_call(address entry, bool emit_delay) { } } - void MacroAssembler::card_table_write(jbyte* byte_map_base, Register tmp, Register obj) { #ifdef _LP64 diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp index d58fc54f1c9..b9e34133328 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp @@ -729,7 +729,11 @@ class MacroAssembler : public Assembler { // Check if the call target is out of wdisp30 range (relative to the code cache) static inline bool is_far_target(address d); inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type ); + inline void call( address d, RelocationHolder const& rspec); + inline void call( Label& L, relocInfo::relocType rt = relocInfo::runtime_call_type ); + inline void call( Label& L, RelocationHolder const& rspec); + inline void callr( Register s1, Register s2 ); inline void callr( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() ); @@ -1146,7 +1150,7 @@ public: void set_vm_result(Register oop_result); // Emit the CompiledIC call idiom - void ic_call(address entry, bool emit_delay = true); + void ic_call(address entry, bool emit_delay = true, jint method_index = 0); // if call_VM_base was called with check_exceptions=false, then call // check_and_forward_exception to handle exceptions when it is safe diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp index 3518d0b6336..4dd8772e010 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp @@ -298,6 +298,10 @@ inline bool MacroAssembler::is_far_target(address d) { // expense of relocation and if we overflow the displacement // of the quick call instruction. inline void MacroAssembler::call( address d, relocInfo::relocType rt ) { + MacroAssembler::call(d, Relocation::spec_simple(rt)); +} + +inline void MacroAssembler::call( address d, RelocationHolder const& rspec ) { #ifdef _LP64 intptr_t disp; // NULL is ok because it will be relocated later. @@ -309,14 +313,14 @@ inline void MacroAssembler::call( address d, relocInfo::relocType rt ) { // Is this address within range of the call instruction? // If not, use the expensive instruction sequence if (is_far_target(d)) { - relocate(rt); + relocate(rspec); AddressLiteral dest(d); jumpl_to(dest, O7, O7); } else { - Assembler::call(d, rt); + Assembler::call(d, rspec); } #else - Assembler::call( d, rt ); + Assembler::call( d, rspec ); #endif } diff --git a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp index 3342f51388e..f08eb5be2f2 100644 --- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp @@ -131,8 +131,9 @@ bool NativeInstruction::is_load_store_with_small_offset(Register reg) { void NativeCall::verify() { NativeInstruction::verify(); // make sure code pattern is actually a call instruction - if (!is_op(long_at(0), Assembler::call_op)) { - fatal("not a call"); + int x = long_at(0); + if (!is_op(x, Assembler::call_op)) { + fatal("not a call: 0x%x @ " INTPTR_FORMAT, x, p2i(instruction_address())); } } diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 15526706f78..510a6a5b156 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -1001,7 +1001,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, PhaseRegAlloc* ra, const MachNode* n, #endif } -void emit_call_reloc(CodeBuffer &cbuf, intptr_t entry_point, relocInfo::relocType rtype, bool preserve_g2 = false) { +void emit_call_reloc(CodeBuffer &cbuf, intptr_t entry_point, RelocationHolder const& rspec, bool preserve_g2 = false) { // The method which records debug information at every safepoint // expects the call to be the first instruction in the snippet as // it creates a PcDesc structure which tracks the offset of a call @@ -1023,7 +1023,7 @@ void emit_call_reloc(CodeBuffer &cbuf, intptr_t entry_point, relocInfo::relocTyp int startpos = __ offset(); #endif /* ASSERT */ - __ call((address)entry_point, rtype); + __ call((address)entry_point, rspec); if (preserve_g2) __ delayed()->mov(G2, L7); else __ delayed()->nop(); @@ -2593,8 +2593,7 @@ encode %{ enc_class Java_To_Runtime (method meth) %{ // CALL Java_To_Runtime // CALL directly to the runtime // The user of this is responsible for ensuring that R_L7 is empty (killed). - emit_call_reloc(cbuf, $meth$$method, relocInfo::runtime_call_type, - /*preserve_g2=*/true); + emit_call_reloc(cbuf, $meth$$method, runtime_call_Relocation::spec(), /*preserve_g2=*/true); %} enc_class preserve_SP %{ @@ -2611,13 +2610,14 @@ encode %{ // CALL to fixup routine. Fixup routine uses ScopeDesc info to determine // who we intended to call. if (!_method) { - emit_call_reloc(cbuf, $meth$$method, relocInfo::runtime_call_type); - } else if (_optimized_virtual) { - emit_call_reloc(cbuf, $meth$$method, relocInfo::opt_virtual_call_type); + emit_call_reloc(cbuf, $meth$$method, runtime_call_Relocation::spec()); } else { - emit_call_reloc(cbuf, $meth$$method, relocInfo::static_call_type); - } - if (_method) { // Emit stub for static call. + int method_index = resolved_method_index(cbuf); + RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) + : static_call_Relocation::spec(method_index); + emit_call_reloc(cbuf, $meth$$method, rspec); + + // Emit stub for static call. address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); // Stub does not fit into scratch buffer if TraceJumps is enabled if (stub == NULL && !(TraceJumps && Compile::current()->in_scratch_emit_size())) { @@ -2638,7 +2638,7 @@ encode %{ Register G5_ic_reg = reg_to_register_object(Matcher::inline_cache_reg_encode()); assert(G5_ic_reg == G5_inline_cache_reg, "G5_inline_cache_reg used in assemble_ic_buffer_code()"); assert(G5_ic_reg == G5_megamorphic_method, "G5_megamorphic_method used in megamorphic call stub"); - __ ic_call((address)$meth$$method); + __ ic_call((address)$meth$$method, /*emit_delay=*/true, resolved_method_index(cbuf)); } else { assert(!UseInlineCaches, "expect vtable calls only if not using ICs"); // Just go thru the vtable @@ -10069,10 +10069,10 @@ instruct string_compareL(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, not format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp" %} ins_encode %{ __ string_compare($str1$$Register, $str2$$Register, - $cnt1$$Register, $cnt2$$Register, + $cnt1$$Register, $cnt2$$Register, $tmp$$Register, $tmp$$Register, $result$$Register, StrIntrinsicNode::LL); - %} + %} ins_pipe(long_memory_op); %} @@ -10088,7 +10088,7 @@ instruct string_compareU(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, not $cnt1$$Register, $cnt2$$Register, $tmp$$Register, $tmp$$Register, $result$$Register, StrIntrinsicNode::UU); - %} + %} ins_pipe(long_memory_op); %} @@ -10104,7 +10104,7 @@ instruct string_compareLU(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, no $cnt1$$Register, $cnt2$$Register, $tmp1$$Register, $tmp2$$Register, $result$$Register, StrIntrinsicNode::LU); - %} + %} ins_pipe(long_memory_op); %} @@ -10117,10 +10117,10 @@ instruct string_compareUL(o0RegP str1, o1RegP str2, g3RegI cnt1, g4RegI cnt2, no format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result // KILL $tmp1,$tmp2" %} ins_encode %{ __ string_compare($str2$$Register, $str1$$Register, - $cnt2$$Register, $cnt1$$Register, + $cnt2$$Register, $cnt1$$Register, $tmp1$$Register, $tmp2$$Register, $result$$Register, StrIntrinsicNode::UL); - %} + %} ins_pipe(long_memory_op); %} diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 21646e1bc0d..69a0d562df1 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -2260,8 +2260,8 @@ void MacroAssembler::call(AddressLiteral entry) { } } -void MacroAssembler::ic_call(address entry) { - RelocationHolder rh = virtual_call_Relocation::spec(pc()); +void MacroAssembler::ic_call(address entry, jint method_index) { + RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); movptr(rax, (intptr_t)Universe::non_oop_word()); call(AddressLiteral(entry, rh)); } diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index b4e440f4383..e29d80b12bb 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -850,7 +850,7 @@ class MacroAssembler: public Assembler { void call(AddressLiteral entry); // Emit the CompiledIC call idiom - void ic_call(address entry); + void ic_call(address entry, jint method_index = 0); // Jumps diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index 1f38927626c..0383a0aa56d 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -1898,17 +1898,18 @@ encode %{ // who we intended to call. cbuf.set_insts_mark(); $$$emit8$primary; + if (!_method) { emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), - runtime_call_Relocation::spec(), RELOC_IMM32 ); - } else if (_optimized_virtual) { - emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), - opt_virtual_call_Relocation::spec(), RELOC_IMM32 ); + runtime_call_Relocation::spec(), + RELOC_IMM32); } else { + int method_index = resolved_method_index(cbuf); + RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) + : static_call_Relocation::spec(method_index); emit_d32_reloc(cbuf, ($meth$$method - (int)(cbuf.insts_end()) - 4), - static_call_Relocation::spec(), RELOC_IMM32 ); - } - if (_method) { // Emit stub for static call. + rspec, RELOC_DISP32); + // Emit stubs for static call. address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); if (stub == NULL) { ciEnv::current()->record_failure("CodeCache is full"); @@ -1919,7 +1920,7 @@ encode %{ enc_class Java_Dynamic_Call (method meth) %{ // JAVA DYNAMIC CALL MacroAssembler _masm(&cbuf); - __ ic_call((address)$meth$$method); + __ ic_call((address)$meth$$method, resolved_method_index(cbuf)); %} enc_class Java_Compiled_Call (method meth) %{ // JAVA COMPILED CALL @@ -11504,7 +11505,7 @@ instruct string_equals(eDIRegP str1, eSIRegP str2, eCXRegI cnt, eAXRegI result, __ arrays_equals(false, $str1$$Register, $str2$$Register, $cnt$$Register, $result$$Register, $tmp3$$Register, $tmp1$$XMMRegister, $tmp2$$XMMRegister, false /* char */); - %} + %} ins_pipe( pipe_slow ); %} diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index 9b4f9f9ebce..9fac082c788 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -2120,22 +2120,15 @@ encode %{ $$$emit8$primary; if (!_method) { - emit_d32_reloc(cbuf, - (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), + emit_d32_reloc(cbuf, (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), runtime_call_Relocation::spec(), RELOC_DISP32); - } else if (_optimized_virtual) { - emit_d32_reloc(cbuf, - (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), - opt_virtual_call_Relocation::spec(), - RELOC_DISP32); } else { - emit_d32_reloc(cbuf, - (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), - static_call_Relocation::spec(), - RELOC_DISP32); - } - if (_method) { + int method_index = resolved_method_index(cbuf); + RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) + : static_call_Relocation::spec(method_index); + emit_d32_reloc(cbuf, (int) ($meth$$method - ((intptr_t) cbuf.insts_end()) - 4), + rspec, RELOC_DISP32); // Emit stubs for static call. address mark = cbuf.insts_mark(); address stub = CompiledStaticCall::emit_to_interp_stub(cbuf, mark); @@ -2148,7 +2141,7 @@ encode %{ enc_class Java_Dynamic_Call(method meth) %{ MacroAssembler _masm(&cbuf); - __ ic_call((address)$meth$$method); + __ ic_call((address)$meth$$method, resolved_method_index(cbuf)); %} enc_class Java_Compiled_Call(method meth) diff --git a/hotspot/src/share/vm/asm/codeBuffer.cpp b/hotspot/src/share/vm/asm/codeBuffer.cpp index 4ffcf0c81a2..30828b69751 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.cpp +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp @@ -305,6 +305,31 @@ address CodeSection::target(Label& L, address branch_pc) { } } +void CodeSection::relocate(address at, relocInfo::relocType rtype, int format, jint method_index) { + RelocationHolder rh; + switch (rtype) { + case relocInfo::none: return; + case relocInfo::opt_virtual_call_type: { + rh = opt_virtual_call_Relocation::spec(method_index); + break; + } + case relocInfo::static_call_type: { + rh = static_call_Relocation::spec(method_index); + break; + } + case relocInfo::virtual_call_type: { + assert(method_index == 0, "resolved method overriding is not supported"); + rh = Relocation::spec_simple(rtype); + break; + } + default: { + rh = Relocation::spec_simple(rtype); + break; + } + } + relocate(at, rh, format); +} + void CodeSection::relocate(address at, RelocationHolder const& spec, int format) { Relocation* reloc = spec.reloc(); relocInfo::relocType rtype = (relocInfo::relocType) reloc->type(); diff --git a/hotspot/src/share/vm/asm/codeBuffer.hpp b/hotspot/src/share/vm/asm/codeBuffer.hpp index 387a5b7cced..534a81f0631 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.hpp +++ b/hotspot/src/share/vm/asm/codeBuffer.hpp @@ -209,10 +209,7 @@ class CodeSection VALUE_OBJ_CLASS_SPEC { // Emit a relocation. void relocate(address at, RelocationHolder const& rspec, int format = 0); - void relocate(address at, relocInfo::relocType rtype, int format = 0) { - if (rtype != relocInfo::none) - relocate(at, Relocation::spec_simple(rtype), format); - } + void relocate(address at, relocInfo::relocType rtype, int format = 0, jint method_index = 0); // alignment requirement for starting offset // Requirements are that the instruction area and the diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index 5b19e95d39f..65edcc30ab5 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -250,6 +250,12 @@ class ciMethod : public ciMetadata { ciField* get_field_at_bci( int bci, bool &will_link); ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature); + ciMethod* get_method_at_bci(int bci) { + bool ignored_will_link; + ciSignature* ignored_declared_signature; + return get_method_at_bci(bci, ignored_will_link, &ignored_declared_signature); + } + // Given a certain calling environment, find the monomorphic target // for the call. Return NULL if the call is not monomorphic in // its calling environment. diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index df477a8462f..e651ad00ed9 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -1054,6 +1054,11 @@ do_name( isCompileConstant_name, "isCompileConstant") \ do_alias( isCompileConstant_signature, object_boolean_signature) \ \ + do_class(sun_hotspot_WhiteBox, "sun/hotspot/WhiteBox") \ + do_intrinsic(_deoptimize, sun_hotspot_WhiteBox, deoptimize_name, deoptimize_signature, F_R) \ + do_name( deoptimize_name, "deoptimize") \ + do_alias( deoptimize_signature, void_method_signature) \ + \ /* unsafe memory references (there are a lot of them...) */ \ do_signature(getObject_signature, "(Ljava/lang/Object;J)Ljava/lang/Object;") \ do_signature(putObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;)V") \ diff --git a/hotspot/src/share/vm/code/compiledIC.cpp b/hotspot/src/share/vm/code/compiledIC.cpp index ec3e3a8e072..b2dde314f54 100644 --- a/hotspot/src/share/vm/code/compiledIC.cpp +++ b/hotspot/src/share/vm/code/compiledIC.cpp @@ -434,7 +434,7 @@ void CompiledIC::set_to_monomorphic(CompiledICInfo& info) { InlineCacheBuffer::create_transition_stub(this, info.cached_metadata(), info.entry()); } else { if (is_optimized()) { - set_ic_destination(info.entry()); + set_ic_destination(info.entry()); } else { set_ic_destination_and_value(info.entry(), info.cached_metadata()); } diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 307f0f71b98..d8af2c0624b 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -978,19 +978,23 @@ void nmethod::print_nmethod(bool printmethod) { oop_maps()->print(); } } - if (PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) { + if (printmethod || PrintDebugInfo || CompilerOracle::has_option_string(_method, "PrintDebugInfo")) { print_scopes(); } - if (PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) { + if (printmethod || PrintRelocations || CompilerOracle::has_option_string(_method, "PrintRelocations")) { print_relocations(); } - if (PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) { + if (printmethod || PrintDependencies || CompilerOracle::has_option_string(_method, "PrintDependencies")) { print_dependencies(); } - if (PrintExceptionHandlers) { + if (printmethod || PrintExceptionHandlers) { print_handler_table(); print_nul_chk_table(); } + if (printmethod) { + print_recorded_oops(); + print_recorded_metadata(); + } if (xtty != NULL) { xtty->tail("print_nmethod"); } @@ -3013,6 +3017,26 @@ void nmethod::print_pcs() { } } +void nmethod::print_recorded_oops() { + tty->print_cr("Recorded oops:"); + for (int i = 0; i < oops_count(); i++) { + oop o = oop_at(i); + tty->print("#%3d: " INTPTR_FORMAT " ", i, p2i(o)); + o->print_value(); + tty->cr(); + } +} + +void nmethod::print_recorded_metadata() { + tty->print_cr("Recorded metadata:"); + for (int i = 0; i < metadata_count(); i++) { + Metadata* m = metadata_at(i); + tty->print("#%3d: " INTPTR_FORMAT " ", i, p2i(m)); + m->print_value_on_maybe_null(tty); + tty->cr(); + } +} + #endif // PRODUCT const char* nmethod::reloc_string_for(u_char* begin, u_char* end) { @@ -3053,9 +3077,39 @@ const char* nmethod::reloc_string_for(u_char* begin, u_char* end) { } return st.as_string(); } - case relocInfo::virtual_call_type: return "virtual_call"; - case relocInfo::opt_virtual_call_type: return "optimized virtual_call"; - case relocInfo::static_call_type: return "static_call"; + case relocInfo::virtual_call_type: { + stringStream st; + st.print_raw("virtual_call"); + virtual_call_Relocation* r = iter.virtual_call_reloc(); + Method* m = r->method_value(); + if (m != NULL) { + assert(m->is_method(), ""); + m->print_short_name(&st); + } + return st.as_string(); + } + case relocInfo::opt_virtual_call_type: { + stringStream st; + st.print_raw("optimized virtual_call"); + opt_virtual_call_Relocation* r = iter.opt_virtual_call_reloc(); + Method* m = r->method_value(); + if (m != NULL) { + assert(m->is_method(), ""); + m->print_short_name(&st); + } + return st.as_string(); + } + case relocInfo::static_call_type: { + stringStream st; + st.print_raw("static_call"); + static_call_Relocation* r = iter.static_call_reloc(); + Method* m = r->method_value(); + if (m != NULL) { + assert(m->is_method(), ""); + m->print_short_name(&st); + } + return st.as_string(); + } case relocInfo::static_stub_type: return "static_stub"; case relocInfo::external_word_type: return "external_word"; case relocInfo::internal_word_type: return "internal_word"; @@ -3393,3 +3447,19 @@ char* nmethod::jvmci_installed_code_name(char* buf, size_t buflen) { return buf; } #endif + +Method* nmethod::attached_method(address call_instr) { + assert(code_contains(call_instr), "not part of the nmethod"); + RelocIterator iter(this, call_instr, call_instr + 1); + while (iter.next()) { + if (iter.addr() == call_instr) { + switch(iter.type()) { + case relocInfo::static_call_type: return iter.static_call_reloc()->method_value(); + case relocInfo::opt_virtual_call_type: return iter.opt_virtual_call_reloc()->method_value(); + case relocInfo::virtual_call_type: return iter.virtual_call_reloc()->method_value(); + } + } + } + return NULL; // not found +} + diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 6134378aac0..3f72547d518 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -392,6 +392,9 @@ class nmethod : public CodeBlob { int handler_table_size() const { return handler_table_end() - handler_table_begin(); } int nul_chk_table_size() const { return nul_chk_table_end() - nul_chk_table_begin(); } + int oops_count() const { assert(oops_size() % oopSize == 0, ""); return (oops_size() / oopSize) + 1; } + int metadata_count() const { assert(metadata_size() % wordSize == 0, ""); return (metadata_size() / wordSize) + 1; } + int total_size () const; void dec_hotness_counter() { _hotness_counter--; } @@ -491,7 +494,7 @@ class nmethod : public CodeBlob { oop oop_at(int index) const { return index == 0 ? (oop) NULL: *oop_addr_at(index); } oop* oop_addr_at(int index) const { // for GC // relocation indexes are biased by 1 (because 0 is reserved) - assert(index > 0 && index <= oops_size(), "must be a valid non-zero index"); + assert(index > 0 && index <= oops_count(), "must be a valid non-zero index"); assert(!_oops_are_stale, "oops are stale"); return &oops_begin()[index - 1]; } @@ -501,13 +504,15 @@ class nmethod : public CodeBlob { Metadata* metadata_at(int index) const { return index == 0 ? NULL: *metadata_addr_at(index); } Metadata** metadata_addr_at(int index) const { // for GC // relocation indexes are biased by 1 (because 0 is reserved) - assert(index > 0 && index <= metadata_size(), "must be a valid non-zero index"); + assert(index > 0 && index <= metadata_count(), "must be a valid non-zero index"); return &metadata_begin()[index - 1]; } void copy_values(GrowableArray* oops); void copy_values(GrowableArray* metadata); + Method* attached_method(address call_pc); + // Relocation support private: void fix_oop_relocations(address begin, address end, bool initialize_immediates); @@ -696,6 +701,8 @@ public: void print_calls(outputStream* st) PRODUCT_RETURN; void print_handler_table() PRODUCT_RETURN; void print_nul_chk_table() PRODUCT_RETURN; + void print_recorded_oops() PRODUCT_RETURN; + void print_recorded_metadata() PRODUCT_RETURN; void print_nmethod(bool print_code); // need to re-define this from CodeBlob else the overload hides it diff --git a/hotspot/src/share/vm/code/relocInfo.cpp b/hotspot/src/share/vm/code/relocInfo.cpp index 50b0517457d..ec83dad64a8 100644 --- a/hotspot/src/share/vm/code/relocInfo.cpp +++ b/hotspot/src/share/vm/code/relocInfo.cpp @@ -581,13 +581,14 @@ void virtual_call_Relocation::pack_data_to(CodeSection* dest) { normalize_address(_cached_value, dest); jint x0 = scaled_offset_null_special(_cached_value, point); - p = pack_1_int_to(p, x0); + p = pack_2_ints_to(p, x0, _method_index); dest->set_locs_end((relocInfo*) p); } void virtual_call_Relocation::unpack_data() { - jint x0 = unpack_1_int(); + jint x0 = 0; + unpack_2_ints(x0, _method_index); address point = addr(); _cached_value = x0==0? NULL: address_from_scaled_offset(x0, point); } @@ -793,6 +794,12 @@ address virtual_call_Relocation::cached_value() { return _cached_value; } +Method* virtual_call_Relocation::method_value() { + Metadata* m = code()->metadata_at(_method_index); + assert(m != NULL || _method_index == 0, "should be non-null for non-zero index"); + assert(m == NULL || m->is_method(), "not a method"); + return (Method*)m; +} void virtual_call_Relocation::clear_inline_cache() { // No stubs for ICs @@ -803,6 +810,23 @@ void virtual_call_Relocation::clear_inline_cache() { } +void opt_virtual_call_Relocation::pack_data_to(CodeSection* dest) { + short* p = (short*) dest->locs_end(); + p = pack_1_int_to(p, _method_index); + dest->set_locs_end((relocInfo*) p); +} + +void opt_virtual_call_Relocation::unpack_data() { + _method_index = unpack_1_int(); +} + +Method* opt_virtual_call_Relocation::method_value() { + Metadata* m = code()->metadata_at(_method_index); + assert(m != NULL || _method_index == 0, "should be non-null for non-zero index"); + assert(m == NULL || m->is_method(), "not a method"); + return (Method*)m; +} + void opt_virtual_call_Relocation::clear_inline_cache() { // No stubs for ICs // Clean IC @@ -827,6 +851,22 @@ address opt_virtual_call_Relocation::static_stub() { return NULL; } +Method* static_call_Relocation::method_value() { + Metadata* m = code()->metadata_at(_method_index); + assert(m != NULL || _method_index == 0, "should be non-null for non-zero index"); + assert(m == NULL || m->is_method(), "not a method"); + return (Method*)m; +} + +void static_call_Relocation::pack_data_to(CodeSection* dest) { + short* p = (short*) dest->locs_end(); + p = pack_1_int_to(p, _method_index); + dest->set_locs_end((relocInfo*) p); +} + +void static_call_Relocation::unpack_data() { + _method_index = unpack_1_int(); +} void static_call_Relocation::clear_inline_cache() { // Safe call site info @@ -1014,6 +1054,12 @@ void RelocIterator::print_current() { break; } case relocInfo::static_call_type: + { + static_call_Relocation* r = (static_call_Relocation*) reloc(); + tty->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]", + p2i(r->destination()), p2i(r->method_value())); + break; + } case relocInfo::runtime_call_type: { CallRelocation* r = (CallRelocation*) reloc(); @@ -1023,8 +1069,8 @@ void RelocIterator::print_current() { case relocInfo::virtual_call_type: { virtual_call_Relocation* r = (virtual_call_Relocation*) reloc(); - tty->print(" | [destination=" INTPTR_FORMAT " cached_value=" INTPTR_FORMAT "]", - p2i(r->destination()), p2i(r->cached_value())); + tty->print(" | [destination=" INTPTR_FORMAT " cached_value=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]", + p2i(r->destination()), p2i(r->cached_value()), p2i(r->method_value())); break; } case relocInfo::static_stub_type: @@ -1039,6 +1085,13 @@ void RelocIterator::print_current() { tty->print(" | [trampoline owner=" INTPTR_FORMAT "]", p2i(r->owner())); break; } + case relocInfo::opt_virtual_call_type: + { + opt_virtual_call_Relocation* r = (opt_virtual_call_Relocation*) reloc(); + tty->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]", + p2i(r->destination()), p2i(r->method_value())); + break; + } } tty->cr(); } diff --git a/hotspot/src/share/vm/code/relocInfo.hpp b/hotspot/src/share/vm/code/relocInfo.hpp index dc9b11bbcfe..a243bfdbee7 100644 --- a/hotspot/src/share/vm/code/relocInfo.hpp +++ b/hotspot/src/share/vm/code/relocInfo.hpp @@ -1044,27 +1044,31 @@ class virtual_call_Relocation : public CallRelocation { // "cached_value" points to the first associated set-oop. // The oop_limit helps find the last associated set-oop. // (See comments at the top of this file.) - static RelocationHolder spec(address cached_value) { + static RelocationHolder spec(address cached_value, jint method_index = 0) { RelocationHolder rh = newHolder(); - new(rh) virtual_call_Relocation(cached_value); + new(rh) virtual_call_Relocation(cached_value, method_index); return rh; } - virtual_call_Relocation(address cached_value) { + private: + address _cached_value; // location of set-value instruction + jint _method_index; // resolved method for a Java call + + virtual_call_Relocation(address cached_value, int method_index) { _cached_value = cached_value; + _method_index = method_index; assert(cached_value != NULL, "first oop address must be specified"); } - private: - address _cached_value; // location of set-value instruction - friend class RelocIterator; virtual_call_Relocation() { } - public: address cached_value(); + int method_index() { return _method_index; } + Method* method_value(); + // data is packed as scaled offsets in "2_ints" format: [f l] or [Ff Ll] // oop_limit is set to 0 if the limit falls somewhere within the call. // When unpacking, a zero oop_limit is taken to refer to the end of the call. @@ -1080,17 +1084,29 @@ class opt_virtual_call_Relocation : public CallRelocation { relocInfo::relocType type() { return relocInfo::opt_virtual_call_type; } public: - static RelocationHolder spec() { + static RelocationHolder spec(int method_index = 0) { RelocationHolder rh = newHolder(); - new(rh) opt_virtual_call_Relocation(); + new(rh) opt_virtual_call_Relocation(method_index); return rh; } private: + jint _method_index; // resolved method for a Java call + + opt_virtual_call_Relocation(int method_index) { + _method_index = method_index; + } + friend class RelocIterator; - opt_virtual_call_Relocation() { } + opt_virtual_call_Relocation() {} public: + int method_index() { return _method_index; } + Method* method_value(); + + void pack_data_to(CodeSection* dest); + void unpack_data(); + void clear_inline_cache(); // find the matching static_stub @@ -1102,17 +1118,29 @@ class static_call_Relocation : public CallRelocation { relocInfo::relocType type() { return relocInfo::static_call_type; } public: - static RelocationHolder spec() { + static RelocationHolder spec(int method_index = 0) { RelocationHolder rh = newHolder(); - new(rh) static_call_Relocation(); + new(rh) static_call_Relocation(method_index); return rh; } private: + jint _method_index; // resolved method for a Java call + + static_call_Relocation(int method_index) { + _method_index = method_index; + } + friend class RelocIterator; - static_call_Relocation() { } + static_call_Relocation() {} public: + int method_index() { return _method_index; } + Method* method_value(); + + void pack_data_to(CodeSection* dest); + void unpack_data(); + void clear_inline_cache(); // find the matching static_stub diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index 173ec0ec667..4c7e891d74a 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -1456,6 +1456,33 @@ void LinkResolver::resolve_invoke(CallInfo& result, Handle recv, const constantP return; } +void LinkResolver::resolve_invoke(CallInfo& result, Handle& recv, + const methodHandle& attached_method, + Bytecodes::Code byte, TRAPS) { + KlassHandle defc = attached_method->method_holder(); + Symbol* name = attached_method->name(); + Symbol* type = attached_method->signature(); + LinkInfo link_info(defc, name, type, KlassHandle(), /*check_access=*/false); + switch(byte) { + case Bytecodes::_invokevirtual: + resolve_virtual_call(result, recv, recv->klass(), link_info, + /*check_null_and_abstract=*/true, CHECK); + break; + case Bytecodes::_invokeinterface: + resolve_interface_call(result, recv, recv->klass(), link_info, + /*check_null_and_abstract=*/true, CHECK); + break; + case Bytecodes::_invokestatic: + resolve_static_call(result, link_info, /*initialize_class=*/false, CHECK); + break; + case Bytecodes::_invokespecial: + resolve_special_call(result, link_info, CHECK); + break; + default: + fatal("bad call: %s", Bytecodes::name(byte)); + } +} + void LinkResolver::resolve_invokestatic(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) { LinkInfo link_info(pool, index, CHECK); resolve_static_call(result, link_info, /*initialize_class*/true, CHECK); diff --git a/hotspot/src/share/vm/interpreter/linkResolver.hpp b/hotspot/src/share/vm/interpreter/linkResolver.hpp index 198eefbe2c0..7d7a27944c8 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp @@ -295,6 +295,12 @@ class LinkResolver: AllStatic { static void resolve_invoke(CallInfo& result, Handle recv, const constantPoolHandle& pool, int index, Bytecodes::Code byte, TRAPS); + + // runtime resolving from attached method + static void resolve_invoke(CallInfo& result, Handle& recv, + const methodHandle& attached_method, + Bytecodes::Code byte, TRAPS); + private: static void trace_method_resolution(const char* prefix, KlassHandle klass, KlassHandle resolved_klass, diff --git a/hotspot/src/share/vm/opto/callGenerator.cpp b/hotspot/src/share/vm/opto/callGenerator.cpp index ff86ad4750d..68a193e246c 100644 --- a/hotspot/src/share/vm/opto/callGenerator.cpp +++ b/hotspot/src/share/vm/opto/callGenerator.cpp @@ -46,6 +46,11 @@ const TypeFunc* CallGenerator::tf() const { return TypeFunc::make(method()); } +bool CallGenerator::is_inlined_mh_linker(JVMState* jvms, ciMethod* callee) { + ciMethod* symbolic_info = jvms->method()->get_method_at_bci(jvms->bci()); + return symbolic_info->is_method_handle_intrinsic() && !callee->is_method_handle_intrinsic(); +} + //-----------------------------ParseGenerator--------------------------------- // Internal class which handles all direct bytecode traversal. class ParseGenerator : public InlineCallGenerator { @@ -137,6 +142,13 @@ JVMState* DirectCallGenerator::generate(JVMState* jvms) { } CallStaticJavaNode *call = new CallStaticJavaNode(kit.C, tf(), target, method(), kit.bci()); + if (is_inlined_mh_linker(jvms, method())) { + // To be able to issue a direct call and skip a call to MH.linkTo*/invokeBasic adapter, + // additional information about the method being invoked should be attached + // to the call site to make resolution logic work + // (see SharedRuntime::resolve_static_call_C). + call->set_override_symbolic_info(true); + } _call_node = call; // Save the call node in case we need it later if (!is_static) { // Make an explicit receiver null_check as part of this call. @@ -192,7 +204,10 @@ JVMState* VirtualCallGenerator::generate(JVMState* jvms) { // the call instruction will have a seemingly deficient out-count. // (The bailout says something misleading about an "infinite loop".) if (kit.gvn().type(receiver)->higher_equal(TypePtr::NULL_PTR)) { - kit.inc_sp(method()->arg_size()); // restore arguments + assert(Bytecodes::is_invoke(kit.java_bc()), "%d: %s", kit.java_bc(), Bytecodes::name(kit.java_bc())); + ciMethod* declared_method = kit.method()->get_method_at_bci(kit.bci()); + int arg_size = declared_method->signature()->arg_size_for_bc(kit.java_bc()); + kit.inc_sp(arg_size); // restore arguments kit.uncommon_trap(Deoptimization::Reason_null_check, Deoptimization::Action_none, NULL, "null receiver"); @@ -226,6 +241,13 @@ JVMState* VirtualCallGenerator::generate(JVMState* jvms) { address target = SharedRuntime::get_resolve_virtual_call_stub(); // Normal inline cache used for call CallDynamicJavaNode *call = new CallDynamicJavaNode(tf(), target, method(), _vtable_index, kit.bci()); + if (is_inlined_mh_linker(jvms, method())) { + // To be able to issue a direct call (optimized virtual or virtual) + // and skip a call to MH.linkTo*/invokeBasic adapter, additional information + // about the method being invoked should be attached to the call site to + // make resolution logic work (see SharedRuntime::resolve_{virtual,opt_virtual}_call_C). + call->set_override_symbolic_info(true); + } kit.set_arguments_for_java_call(call); kit.set_edges_for_java_call(call); Node* ret = kit.set_results_for_java_call(call); @@ -463,8 +485,8 @@ bool LateInlineMHCallGenerator::do_late_inline_check(JVMState* jvms) { _attempt++; } - if (cg != NULL) { - assert(!cg->is_late_inline() && cg->is_inline(), "we're doing late inlining"); + if (cg != NULL && cg->is_inline()) { + assert(!cg->is_late_inline(), "we're doing late inlining"); _inline_cg = cg; Compile::current()->dec_number_of_mh_late_inlines(); return true; @@ -807,8 +829,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* const int vtable_index = Method::invalid_vtable_index; CallGenerator* cg = C->call_generator(target, vtable_index, false, jvms, true, PROB_ALWAYS, NULL, true, true); assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here"); - if (cg != NULL && cg->is_inline()) - return cg; + return cg; } else { const char* msg = "receiver not constant"; if (PrintInlining) C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg); @@ -829,7 +850,7 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* const TypeOopPtr* oop_ptr = member_name->bottom_type()->is_oopptr(); ciMethod* target = oop_ptr->const_oop()->as_member_name()->get_vmtarget(); - // In lamda forms we erase signature types to avoid resolving issues + // In lambda forms we erase signature types to avoid resolving issues // involving class loaders. When we optimize a method handle invoke // to a direct call we must cast the receiver and arguments to its // actual types. @@ -882,10 +903,9 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* // provide us with a type speculative_receiver_type = (receiver_type != NULL) ? receiver_type->speculative_type() : NULL; } - CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, true, PROB_ALWAYS, speculative_receiver_type, true, true); + CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, /*allow_inline=*/true, PROB_ALWAYS, speculative_receiver_type, true, true); assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here"); - if (cg != NULL && cg->is_inline()) - return cg; + return cg; } else { const char* msg = "member_name not constant"; if (PrintInlining) C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg); diff --git a/hotspot/src/share/vm/opto/callGenerator.hpp b/hotspot/src/share/vm/opto/callGenerator.hpp index 238fba2ce4a..58e8fe9c614 100644 --- a/hotspot/src/share/vm/opto/callGenerator.hpp +++ b/hotspot/src/share/vm/opto/callGenerator.hpp @@ -49,7 +49,7 @@ class CallGenerator : public ResourceObj { public: // Accessors - ciMethod* method() const { return _method; } + ciMethod* method() const { return _method; } // is_inline: At least some code implementing the method is copied here. virtual bool is_inline() const { return false; } @@ -123,7 +123,6 @@ class CallGenerator : public ResourceObj { // How to generate vanilla out-of-line call sites: static CallGenerator* for_direct_call(ciMethod* m, bool separate_io_projs = false); // static, special static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index); // virtual, interface - static CallGenerator* for_dynamic_call(ciMethod* m); // invokedynamic static CallGenerator* for_method_handle_call( JVMState* jvms, ciMethod* caller, ciMethod* callee, bool delayed_forbidden); static CallGenerator* for_method_handle_inline(JVMState* jvms, ciMethod* caller, ciMethod* callee, bool& input_not_const); @@ -170,6 +169,8 @@ class CallGenerator : public ResourceObj { C->print_inlining(callee, inline_level, bci, msg); } } + + static bool is_inlined_mh_linker(JVMState* jvms, ciMethod* m); }; diff --git a/hotspot/src/share/vm/opto/callnode.cpp b/hotspot/src/share/vm/opto/callnode.cpp index c82a149d444..581b6d3bd67 100644 --- a/hotspot/src/share/vm/opto/callnode.cpp +++ b/hotspot/src/share/vm/opto/callnode.cpp @@ -959,7 +959,8 @@ bool CallNode::is_call_to_arraycopystub() const { uint CallJavaNode::size_of() const { return sizeof(*this); } uint CallJavaNode::cmp( const Node &n ) const { CallJavaNode &call = (CallJavaNode&)n; - return CallNode::cmp(call) && _method == call._method; + return CallNode::cmp(call) && _method == call._method && + _override_symbolic_info == call._override_symbolic_info; } #ifndef PRODUCT void CallJavaNode::dump_spec(outputStream *st) const { diff --git a/hotspot/src/share/vm/opto/callnode.hpp b/hotspot/src/share/vm/opto/callnode.hpp index 389f09cab07..40f939a1160 100644 --- a/hotspot/src/share/vm/opto/callnode.hpp +++ b/hotspot/src/share/vm/opto/callnode.hpp @@ -657,25 +657,29 @@ protected: bool _optimized_virtual; bool _method_handle_invoke; - ciMethod* _method; // Method being direct called + bool _override_symbolic_info; // Override symbolic call site info from bytecode + ciMethod* _method; // Method being direct called public: const int _bci; // Byte Code Index of call byte code CallJavaNode(const TypeFunc* tf , address addr, ciMethod* method, int bci) : CallNode(tf, addr, TypePtr::BOTTOM), _method(method), _bci(bci), _optimized_virtual(false), - _method_handle_invoke(false) + _method_handle_invoke(false), + _override_symbolic_info(false) { init_class_id(Class_CallJava); } virtual int Opcode() const; - ciMethod* method() const { return _method; } - void set_method(ciMethod *m) { _method = m; } - void set_optimized_virtual(bool f) { _optimized_virtual = f; } - bool is_optimized_virtual() const { return _optimized_virtual; } - void set_method_handle_invoke(bool f) { _method_handle_invoke = f; } - bool is_method_handle_invoke() const { return _method_handle_invoke; } + ciMethod* method() const { return _method; } + void set_method(ciMethod *m) { _method = m; } + void set_optimized_virtual(bool f) { _optimized_virtual = f; } + bool is_optimized_virtual() const { return _optimized_virtual; } + void set_method_handle_invoke(bool f) { _method_handle_invoke = f; } + bool is_method_handle_invoke() const { return _method_handle_invoke; } + void set_override_symbolic_info(bool f) { _override_symbolic_info = f; } + bool override_symbolic_info() const { return _override_symbolic_info; } #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; diff --git a/hotspot/src/share/vm/opto/doCall.cpp b/hotspot/src/share/vm/opto/doCall.cpp index b8737560b07..1e8c1a465dc 100644 --- a/hotspot/src/share/vm/opto/doCall.cpp +++ b/hotspot/src/share/vm/opto/doCall.cpp @@ -393,6 +393,100 @@ bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* kl return false; } +#ifdef ASSERT +static bool check_type(ciType* t1, ciType* t2) { + // Either oop-oop or prim-prim pair. + if (t1->is_primitive_type() && t2->is_primitive_type()) { + return t1->size() == t2->size(); // argument sizes should match + } else { + return !t1->is_primitive_type() && !t2->is_primitive_type(); // oop-oop + } +} + +static bool check_inlined_mh_linker_info(ciMethod* symbolic_info, ciMethod* resolved_method) { + assert(symbolic_info->is_method_handle_intrinsic(), "sanity"); + assert(!resolved_method->is_method_handle_intrinsic(), "sanity"); + + if (!symbolic_info->is_loaded() || !resolved_method->is_loaded()) { + return true; // Don't compare unloaded methods. + } + // Linkers have appendix argument which is not passed to callee. + int has_appendix = MethodHandles::has_member_arg(symbolic_info->intrinsic_id()) ? 1 : 0; + if (symbolic_info->arg_size() != (resolved_method->arg_size() + has_appendix)) { + return false; // Total size of arguments on stack mismatch. + } + if (!check_type(symbolic_info->return_type(), resolved_method->return_type())) { + return false; // Return value size or type mismatch encountered. + } + + switch (symbolic_info->intrinsic_id()) { + case vmIntrinsics::_linkToVirtual: + case vmIntrinsics::_linkToInterface: + case vmIntrinsics::_linkToSpecial: { + if (resolved_method->is_static()) return false; + break; + } + case vmIntrinsics::_linkToStatic: { + if (!resolved_method->is_static()) return false; + break; + } + } + + ciSignature* symbolic_sig = symbolic_info->signature(); + ciSignature* resolved_sig = resolved_method->signature(); + + if (symbolic_sig->count() + (symbolic_info->is_static() ? 0 : 1) != + resolved_sig->count() + (resolved_method->is_static() ? 0 : 1) + has_appendix) { + return false; // Argument count mismatch + } + + int sbase = 0, rbase = 0; + int arg_count = MIN2(symbolic_sig->count() - has_appendix, resolved_sig->count()); + ciType* recv_type = NULL; + if (symbolic_info->is_static() && !resolved_method->is_static()) { + recv_type = symbolic_sig->type_at(0); + sbase = 1; + } else if (!symbolic_info->is_static() && resolved_method->is_static()) { + recv_type = resolved_sig->type_at(0); + rbase = 1; + } + if (recv_type != NULL && recv_type->is_primitive_type()) { + return false; // Receiver should be an oop. + } + for (int i = 0; i < arg_count; i++) { + if (!check_type(symbolic_sig->type_at(sbase + i), resolved_sig->type_at(rbase + i))) { + return false; // Argument size or type mismatch encountered. + } + } + return true; +} + +static bool is_call_consistent_with_jvms(JVMState* jvms, CallGenerator* cg) { + ciMethod* symbolic_info = jvms->method()->get_method_at_bci(jvms->bci()); + ciMethod* resolved_method = cg->method(); + + if (CallGenerator::is_inlined_mh_linker(jvms, resolved_method)) { + return check_inlined_mh_linker_info(symbolic_info, resolved_method); + } else { + // Method name & descriptor should stay the same. + return (symbolic_info->get_Method()->name() == resolved_method->get_Method()->name()) && + (symbolic_info->get_Method()->signature() == resolved_method->get_Method()->signature()); + } +} + +static bool check_call_consistency(JVMState* jvms, CallGenerator* cg) { + if (!is_call_consistent_with_jvms(jvms, cg)) { + tty->print_cr("JVMS:"); + jvms->dump(); + tty->print_cr("Bytecode info:"); + jvms->method()->get_method_at_bci(jvms->bci())->print(); tty->cr(); + tty->print_cr("Resolved method:"); + cg->method()->print(); tty->cr(); + return false; + } + return true; +} +#endif // ASSERT //------------------------------do_call---------------------------------------- // Handle your basic call. Inline if we can & want to, else just setup call. @@ -571,6 +665,8 @@ void Parse::do_call() { set_jvms(new_jvms); } + assert(check_call_consistency(jvms, cg), "inconsistent info"); + if (!stopped()) { // This was some sort of virtual call, which did a null check for us. // Now we can assert receiver-not-null, on the normal return path. diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index ff068a7fd55..694fb6f6834 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -315,6 +315,8 @@ class LibraryCallKit : public GraphKit { bool inline_profileBoolean(); bool inline_isCompileConstant(); + + bool inline_deoptimize(); }; //---------------------------make_vm_intrinsic---------------------------- @@ -750,6 +752,9 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_hasNegatives: return inline_hasNegatives(); + case vmIntrinsics::_deoptimize: + return inline_deoptimize(); + default: // If you get here, it may be that someone has added a new intrinsic // to the list in vmSymbols.hpp without implementing it here. @@ -6574,3 +6579,12 @@ bool LibraryCallKit::inline_isCompileConstant() { set_result(n->is_Con() ? intcon(1) : intcon(0)); return true; } + +bool LibraryCallKit::inline_deoptimize() { + assert(WhiteBoxAPI, ""); + PreserveReexecuteState preexecs(this); + jvms()->set_should_reexecute(false); + uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_none); + return true; +} diff --git a/hotspot/src/share/vm/opto/machnode.cpp b/hotspot/src/share/vm/opto/machnode.cpp index c780d3f5340..c4e6953ab9f 100644 --- a/hotspot/src/share/vm/opto/machnode.cpp +++ b/hotspot/src/share/vm/opto/machnode.cpp @@ -707,7 +707,8 @@ const RegMask &MachCallNode::in_RegMask(uint idx) const { uint MachCallJavaNode::size_of() const { return sizeof(*this); } uint MachCallJavaNode::cmp( const Node &n ) const { MachCallJavaNode &call = (MachCallJavaNode&)n; - return MachCallNode::cmp(call) && _method->equals(call._method); + return MachCallNode::cmp(call) && _method->equals(call._method) && + _override_symbolic_info == call._override_symbolic_info; } #ifndef PRODUCT void MachCallJavaNode::dump_spec(outputStream *st) const { diff --git a/hotspot/src/share/vm/opto/machnode.hpp b/hotspot/src/share/vm/opto/machnode.hpp index ca2ad70c264..25cbdc648e7 100644 --- a/hotspot/src/share/vm/opto/machnode.hpp +++ b/hotspot/src/share/vm/opto/machnode.hpp @@ -885,16 +885,28 @@ protected: virtual uint cmp( const Node &n ) const; virtual uint size_of() const; // Size is bigger public: - ciMethod* _method; // Method being direct called - int _bci; // Byte Code index of call byte code - bool _optimized_virtual; // Tells if node is a static call or an optimized virtual - bool _method_handle_invoke; // Tells if the call has to preserve SP - MachCallJavaNode() : MachCallNode() { + ciMethod* _method; // Method being direct called + bool _override_symbolic_info; // Override symbolic call site info from bytecode + int _bci; // Byte Code index of call byte code + bool _optimized_virtual; // Tells if node is a static call or an optimized virtual + bool _method_handle_invoke; // Tells if the call has to preserve SP + MachCallJavaNode() : MachCallNode(), _override_symbolic_info(false) { init_class_id(Class_MachCallJava); } virtual const RegMask &in_RegMask(uint) const; + int resolved_method_index(CodeBuffer &cbuf) const { + if (_override_symbolic_info) { + // Attach corresponding Method* to the call site, so VM can use it during resolution + // instead of querying symbolic info from bytecode. + assert(_method != NULL, "method should be set"); + assert(_method->constant_encoding()->is_method(), "should point to a Method"); + return cbuf.oop_recorder()->find_index(_method->constant_encoding()); + } + return 0; // Use symbolic info from bytecode (resolved_method == NULL). + } + #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index acf3f32ece0..bb18a3da6d8 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -1201,6 +1201,7 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) { mcall_java->_optimized_virtual = call_java->is_optimized_virtual(); is_method_handle_invoke = call_java->is_method_handle_invoke(); mcall_java->_method_handle_invoke = is_method_handle_invoke; + mcall_java->_override_symbolic_info = call_java->override_symbolic_info(); if (is_method_handle_invoke) { C->set_has_method_handle_invokes(true); } diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index 99e8a785f10..4f21e410c24 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -358,6 +358,19 @@ Symbol* MethodHandles::signature_polymorphic_intrinsic_name(vmIntrinsics::ID iid return 0; } +Bytecodes::Code MethodHandles::signature_polymorphic_intrinsic_bytecode(vmIntrinsics::ID id) { + switch(id) { + case vmIntrinsics::_linkToVirtual: return Bytecodes::_invokevirtual; + case vmIntrinsics::_linkToInterface: return Bytecodes::_invokeinterface; + case vmIntrinsics::_linkToStatic: return Bytecodes::_invokestatic; + case vmIntrinsics::_linkToSpecial: return Bytecodes::_invokespecial; + case vmIntrinsics::_invokeBasic: return Bytecodes::_invokehandle; + default: + fatal("unexpected id: (%d) %s", (uint)id, vmIntrinsics::name_at(id)); + return Bytecodes::_illegal; + } +} + int MethodHandles::signature_polymorphic_intrinsic_ref_kind(vmIntrinsics::ID iid) { switch (iid) { case vmIntrinsics::_invokeBasic: return 0; diff --git a/hotspot/src/share/vm/prims/methodHandles.hpp b/hotspot/src/share/vm/prims/methodHandles.hpp index ab41c31b4a3..22205f2e9da 100644 --- a/hotspot/src/share/vm/prims/methodHandles.hpp +++ b/hotspot/src/share/vm/prims/methodHandles.hpp @@ -91,6 +91,10 @@ class MethodHandles: AllStatic { iid <= vmIntrinsics::LAST_MH_SIG_POLY); } + static bool is_signature_polymorphic_method(Method* m) { + return is_signature_polymorphic(m->intrinsic_id()); + } + static bool is_signature_polymorphic_intrinsic(vmIntrinsics::ID iid) { assert(is_signature_polymorphic(iid), ""); // Most sig-poly methods are intrinsics which do not require an @@ -131,6 +135,8 @@ class MethodHandles: AllStatic { return signature_polymorphic_name_id(klass, name) != vmIntrinsics::_none; } + static Bytecodes::Code signature_polymorphic_intrinsic_bytecode(vmIntrinsics::ID id); + static int get_named_constant(int which, Handle name_box, TRAPS); public: diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 6c68a00d29c..c627ee3ca60 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -1290,6 +1290,11 @@ WB_ENTRY(jlong, WB_GetConstantPool(JNIEnv* env, jobject wb, jclass klass)) return (jlong) ikh->constants(); WB_END +WB_ENTRY(void, WB_ClearInlineCaches(JNIEnv* env, jobject wb)) + VM_ClearICs clear_ics; + VMThread::execute(&clear_ics); +WB_END + template static bool GetMethodOption(JavaThread* thread, JNIEnv* env, jobject method, jstring name, T* value) { assert(value != NULL, "sanity"); @@ -1615,6 +1620,7 @@ static JNINativeMethod methods[] = { (void*)&WB_GetMethodStringOption}, {CC"isShared", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsShared }, {CC"areSharedStringsIgnored", CC"()Z", (void*)&WB_AreSharedStringsIgnored }, + {CC"clearInlineCaches", CC"()V", (void*)&WB_ClearInlineCaches }, }; #undef CC diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index 68440ee89cf..a79ae71fbc6 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -1070,6 +1070,21 @@ Handle SharedRuntime::find_callee_info(JavaThread* thread, Bytecodes::Code& bc, return find_callee_info_helper(thread, vfst, bc, callinfo, THREAD); } +methodHandle SharedRuntime::extract_attached_method(vframeStream& vfst) { + nmethod* caller_nm = vfst.nm(); + + nmethodLocker caller_lock(caller_nm); + + address pc = vfst.frame_pc(); + { // Get call instruction under lock because another thread may be busy patching it. + MutexLockerEx ml_patch(Patching_lock, Mutex::_no_safepoint_check_flag); + if (NativeCall::is_call_before(pc)) { + NativeCall* ncall = nativeCall_before(pc); + return caller_nm->attached_method(ncall->instruction_address()); + } + } + return NULL; +} // Finds receiver, CallInfo (i.e. receiver method), and calling bytecode // for a call current in progress, i.e., arguments has been pushed on stack @@ -1087,15 +1102,37 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread, methodHandle caller(THREAD, vfst.method()); int bci = vfst.bci(); - // Find bytecode Bytecode_invoke bytecode(caller, bci); - bc = bytecode.invoke_code(); int bytecode_index = bytecode.index(); + methodHandle attached_method = extract_attached_method(vfst); + if (attached_method.not_null()) { + methodHandle callee = bytecode.static_target(CHECK_NH); + vmIntrinsics::ID id = callee->intrinsic_id(); + // When VM replaces MH.invokeBasic/linkTo* call with a direct/virtual call, + // it attaches statically resolved method to the call site. + if (MethodHandles::is_signature_polymorphic(id) && + 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; + } + } + } else { + bc = bytecode.invoke_code(); + } + + bool has_receiver = bc != Bytecodes::_invokestatic && + bc != Bytecodes::_invokedynamic && + bc != Bytecodes::_invokehandle; + // Find receiver for non-static call - if (bc != Bytecodes::_invokestatic && - bc != Bytecodes::_invokedynamic && - bc != Bytecodes::_invokehandle) { + if (has_receiver) { // This register map must be update since we need to find the receiver for // compiled frames. The receiver might be in a register. RegisterMap reg_map2(thread); @@ -1103,10 +1140,13 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread, // Caller-frame is a compiled frame frame callerFrame = stubFrame.sender(®_map2); - methodHandle callee = bytecode.static_target(CHECK_(nullHandle)); - if (callee.is_null()) { - THROW_(vmSymbols::java_lang_NoSuchMethodException(), nullHandle); + if (attached_method.is_null()) { + methodHandle callee = bytecode.static_target(CHECK_NH); + if (callee.is_null()) { + THROW_(vmSymbols::java_lang_NoSuchMethodException(), nullHandle); + } } + // Retrieve from a compiled argument list receiver = Handle(THREAD, callerFrame.retrieve_receiver(®_map2)); @@ -1115,26 +1155,35 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread, } } - // Resolve method. This is parameterized by bytecode. - constantPoolHandle constants(THREAD, caller->constants()); assert(receiver.is_null() || receiver->is_oop(), "wrong receiver"); - LinkResolver::resolve_invoke(callinfo, receiver, constants, bytecode_index, bc, CHECK_(nullHandle)); + + // Resolve method + if (attached_method.not_null()) { + // Parameterized by attached method. + LinkResolver::resolve_invoke(callinfo, receiver, attached_method, bc, CHECK_NH); + } else { + // Parameterized by bytecode. + constantPoolHandle constants(THREAD, caller->constants()); + LinkResolver::resolve_invoke(callinfo, receiver, constants, bytecode_index, bc, CHECK_NH); + } #ifdef ASSERT // Check that the receiver klass is of the right subtype and that it is initialized for virtual calls - if (bc != Bytecodes::_invokestatic && bc != Bytecodes::_invokedynamic && bc != Bytecodes::_invokehandle) { + if (has_receiver) { assert(receiver.not_null(), "should have thrown exception"); KlassHandle receiver_klass(THREAD, receiver->klass()); - Klass* rk = constants->klass_ref_at(bytecode_index, CHECK_(nullHandle)); - // klass is already loaded + Klass* rk = NULL; + if (attached_method.not_null()) { + // In case there's resolved method attached, use its holder during the check. + rk = attached_method->method_holder(); + } else { + // Klass is already loaded. + constantPoolHandle constants(THREAD, caller->constants()); + rk = constants->klass_ref_at(bytecode_index, CHECK_NH); + } KlassHandle static_receiver_klass(THREAD, rk); - // Method handle invokes might have been optimized to a direct call - // so don't check for the receiver class. - // FIXME this weakens the assert too much methodHandle callee = callinfo.selected_method(); - assert(receiver_klass->is_subtype_of(static_receiver_klass()) || - callee->is_method_handle_intrinsic() || - callee->is_compiled_lambda_form(), + assert(receiver_klass->is_subtype_of(static_receiver_klass()), "actual receiver must be subclass of static receiver klass"); if (receiver_klass->is_instance_klass()) { if (InstanceKlass::cast(receiver_klass())->is_not_initialized()) { @@ -1670,7 +1719,6 @@ methodHandle SharedRuntime::reresolve_call_site(JavaThread *thread, TRAPS) { inline_cache->set_to_clean(); } } - } methodHandle callee_method = find_callee_method(thread, CHECK_(methodHandle())); diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp index acf822f6eb1..39fc4ce818a 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp @@ -343,6 +343,8 @@ class SharedRuntime: AllStatic { Bytecodes::Code& bc, CallInfo& callinfo, TRAPS); + static methodHandle extract_attached_method(vframeStream& vfst); + static address clean_virtual_call_entry(); static address clean_opt_virtual_call_entry(); static address clean_static_call_entry(); diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index ac53ea63913..940f801f170 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -30,6 +30,7 @@ #include "oops/oop.hpp" #include "runtime/thread.hpp" #include "utilities/top.hpp" +#include "code/codeCache.hpp" // The following classes are used for operations // initiated by a Java thread but that must @@ -44,6 +45,7 @@ template(ThreadDump) \ template(PrintThreads) \ template(FindDeadlocks) \ + template(ClearICs) \ template(ForceSafepoint) \ template(ForceAsyncSafepoint) \ template(Deoptimize) \ @@ -230,6 +232,13 @@ class VM_ThreadStop: public VM_Operation { } }; +class VM_ClearICs: public VM_Operation { + public: + VM_ClearICs() {} + void doit() { CodeCache::clear_inline_caches(); } + VMOp_Type type() const { return VMOp_ClearICs; } +}; + // dummy vm op, evaluated just to force a safepoint class VM_ForceSafepoint: public VM_Operation { public: diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java b/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java new file mode 100644 index 00000000000..415f0b6b903 --- /dev/null +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java @@ -0,0 +1,48 @@ +/* + * 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. + */ +import java.io.File; +import java.io.PrintStream; +import java.lang.instrument.Instrumentation; +import java.util.Arrays; + +public class Agent { + public static void main(String[] args) throws Exception { + String jarName = args[0]; + String className = args[1]; + String manifestName = "manifest.mf"; + + System.out.println("Creating "+manifestName); + try (PrintStream out = new PrintStream(new File(manifestName))) { + out.println("Premain-Class: " + className); + out.println("Can-Redefine-Classes: true"); + } + System.out.println("Building "+jarName); + String[] jarArgs = new String[] {"-cfm", jarName, manifestName }; + + System.out.println("Running jar " + Arrays.toString(jarArgs)); + sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar"); + if (!jarTool.run(jarArgs)) { + throw new Error("jar failed: args=" + Arrays.toString(args)); + } + } +} diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java new file mode 100644 index 00000000000..0a325734db4 --- /dev/null +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java @@ -0,0 +1,105 @@ +/* + * 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 8072008 + * @library /testlibrary /../../test/lib + * @build GCTest NonInlinedReinvoker + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * java.lang.invoke.GCTest + * java.lang.invoke.GCTest$T + * java.lang.invoke.NonInlinedReinvoker + * jdk.test.lib.Asserts + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 + * java.lang.invoke.GCTest + */ +package java.lang.invoke; + +import sun.hotspot.WhiteBox; + +import java.lang.ref.*; +import static jdk.test.lib.Asserts.*; + +public class GCTest { + static final MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP; + + static class T { + static int f1() { return 0; } + static int f2() { return 1; } + } + + static @Stable MethodHandle mh; + static PhantomReference lform; + + static final ReferenceQueue rq = new ReferenceQueue<>(); + static final WhiteBox WB = WhiteBox.getWhiteBox(); + + @DontInline + static int invokeBasic() { + try { + return (int) mh.invokeBasic(); + } catch (Throwable e) { + throw new Error(e); + } + } + + static void test(int expected) { + for (int i = 0; i < 20_000; i++) { + invokeBasic(); + } + assertEquals(invokeBasic(), expected); + } + + public static void main(String[] args) throws Exception { + mh = NonInlinedReinvoker.make( + LOOKUP.findStatic(T.class, "f1", MethodType.methodType(int.class))); + + // Monitor LambdaForm GC + lform = new PhantomReference<>(mh.form, rq); + + test(0); + WB.clearInlineCaches(); + test(0); + + mh = NonInlinedReinvoker.make( + LOOKUP.findStatic(T.class, "f2", MethodType.methodType(int.class))); + + Reference ref = null; + while (ref == null) { + WB.fullGC(); + try { + ref = rq.remove(1000); + } catch (InterruptedException e) { /*ignore*/ } + } + + test(1); + WB.clearInlineCaches(); + test(1); + + System.out.println("TEST PASSED"); + } +} diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java new file mode 100644 index 00000000000..687ef7242a7 --- /dev/null +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java @@ -0,0 +1,218 @@ +/* + * 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 8072008 + * @library /testlibrary /../../test/lib + * @build InvokeTest NonInlinedReinvoker + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * java.lang.invoke.InvokeTest + * java.lang.invoke.InvokeTest$T + * java.lang.invoke.InvokeTest$P1 + * java.lang.invoke.InvokeTest$P2 + * java.lang.invoke.InvokeTest$I + * java.lang.invoke.NonInlinedReinvoker + * jdk.test.lib.Asserts + * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 + * java.lang.invoke.InvokeTest + */ +package java.lang.invoke; + +import sun.hotspot.WhiteBox; +import static jdk.test.lib.Asserts.*; + +public class InvokeTest { + static MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP; + + static final MethodHandle virtualMH; // invokevirtual T.f1 + static final MethodHandle staticMH; // invokestatic T.f2 + static final MethodHandle intfMH; // invokeinterface I.f1 + static final MethodHandle specialMH; // invokespecial T.f4 T + static final MethodHandle basicMH; + + static final WhiteBox WB = WhiteBox.getWhiteBox(); + + static volatile boolean doDeopt = false; + + static { + try { + MethodType mtype = MethodType.methodType(Class.class); + + virtualMH = LOOKUP.findVirtual(T.class, "f1", mtype); + staticMH = LOOKUP.findStatic (T.class, "f2", mtype); + intfMH = LOOKUP.findVirtual(I.class, "f3", mtype); + specialMH = LOOKUP.findSpecial(T.class, "f4", mtype, T.class); + basicMH = NonInlinedReinvoker.make(staticMH); + } catch (Exception e) { + throw new Error(e); + } + } + + static class T implements I { + @DontInline public Class f1() { if (doDeopt) WB.deoptimize(); return T.class; } + @DontInline public static Class f2() { if (doDeopt) WB.deoptimize(); return T.class; } + @DontInline private Class f4() { if (doDeopt) WB.deoptimize(); return T.class; } + } + + static class P1 extends T { + @DontInline public Class f1() { if (doDeopt) WB.deoptimize(); return P1.class; } + @DontInline public Class f3() { if (doDeopt) WB.deoptimize(); return P1.class; } + } + + static class P2 extends T { + @DontInline public Class f1() { if (doDeopt) WB.deoptimize(); return P2.class; } + @DontInline public Class f3() { if (doDeopt) WB.deoptimize(); return P2.class; } + } + + static interface I { + @DontInline default Class f3() { if (doDeopt) WB.deoptimize(); return I.class; } + } + + @DontInline + static void linkToVirtual(Object obj, Class extecpted) { + try { + Class cls = (Class)virtualMH.invokeExact((T)obj); + assertEquals(cls, obj.getClass()); + } catch (Throwable e) { + throw new Error(e); + } + } + + @DontInline + static void linkToInterface(Object obj, Class expected) { + try { + Class cls = (Class)intfMH.invokeExact((I)obj); + assertEquals(cls, expected); + } catch (Throwable e) { + throw new Error(e); + } + } + + @DontInline + static void linkToStatic() { + try { + Class cls = (Class)staticMH.invokeExact(); + assertEquals(cls, T.class); + } catch (Throwable e) { + throw new Error(e); + } + } + + @DontInline + static void linkToSpecial(Object obj, Class expected) { + try { + Class cls = (Class)specialMH.invokeExact((T)obj); + assertEquals(cls, expected); + } catch (Throwable e) { + throw new Error(e); + } + } + + @DontInline + static void invokeBasic() { + try { + Class cls = (Class)basicMH.invokeBasic(); + assertEquals(cls, T.class); + } catch (Throwable e) { + throw new Error(e); + } + } + + static void run(Runnable r) { + for (int i = 0; i < 20_000; i++) { + r.run(); + } + + doDeopt = true; + r.run(); + doDeopt = false; + + WB.clearInlineCaches(); + + for (int i = 0; i < 20_000; i++) { + r.run(); + } + + doDeopt = true; + r.run(); + doDeopt = false; + } + + static void testVirtual() { + System.out.println("linkToVirtual"); + + // Monomorphic case (optimized virtual call) + run(() -> linkToVirtual(new T(), T.class)); + + // Megamorphic case (virtual call) + Object[] recv = new Object[] { new T(), new P1(), new P2() }; + run(() -> { + for (Object r : recv) { + linkToVirtual(r, r.getClass()); + }}); + } + + static void testInterface() { + System.out.println("linkToInterface"); + + // Monomorphic case (optimized virtual call) + run(() -> linkToInterface(new T(), I.class)); + + // Megamorphic case (virtual call) + Object[][] recv = new Object[][] {{new T(), I.class}, {new P1(), P1.class}, {new P2(), P2.class}}; + run(() -> { + for (Object[] r : recv) { + linkToInterface(r[0], (Class)r[1]); + }}); + } + + static void testSpecial() { + System.out.println("linkToSpecial"); + // Monomorphic case (optimized virtual call) + run(() -> linkToSpecial(new T(), T.class)); + } + + static void testStatic() { + System.out.println("linkToStatic"); + // static call + run(() -> linkToStatic()); + } + + static void testBasic() { + System.out.println("invokeBasic"); + // static call + run(() -> invokeBasic()); + } + + public static void main(String[] args) { + testVirtual(); + testInterface(); + testSpecial(); + testStatic(); + testBasic(); + } +} diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/NonInlinedReinvoker.java b/hotspot/test/compiler/jsr292/NonInlinedCall/NonInlinedReinvoker.java new file mode 100644 index 00000000000..c4c36d3c49d --- /dev/null +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/NonInlinedReinvoker.java @@ -0,0 +1,48 @@ +/* + * 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. + */ +package java.lang.invoke; + +class NonInlinedReinvoker extends DelegatingMethodHandle { + private final MethodHandle target; + + private NonInlinedReinvoker(MethodHandle target, LambdaForm lf) { + super(target.type(), lf); + this.target = target; + } + @Override + protected MethodHandle getTarget() { + return target; + } + + @Override + MethodHandle asTypeUncached(MethodType newType) { + return asTypeCache = target.asType(newType); + } + + static MethodHandle make(MethodHandle target) { + LambdaForm lform = DelegatingMethodHandle.makeReinvokerForm( + target, -1, DelegatingMethodHandle.class, "reinvoker.dontInline", + /*forceInline=*/false, DelegatingMethodHandle.NF_getTarget, null); + return new NonInlinedReinvoker(target, lform); + } +} diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java new file mode 100644 index 00000000000..54ce2221390 --- /dev/null +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java @@ -0,0 +1,157 @@ +/* + * 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 8072008 + * @library /testlibrary /../../test/lib + * @build RedefineTest Agent + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * java.lang.invoke.RedefineTest + * Agent + * jdk.test.lib.Asserts + * @run main Agent agent.jar java.lang.invoke.RedefineTest + * @run main/othervm -Xbootclasspath/a:. -javaagent:agent.jar + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 + * java.lang.invoke.RedefineTest + */ +package java.lang.invoke; + +import sun.hotspot.WhiteBox; +import sun.misc.Unsafe; + +import jdk.internal.org.objectweb.asm.*; + +import java.lang.instrument.ClassDefinition; +import java.lang.instrument.Instrumentation; + +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +public class RedefineTest { + static final MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP; + static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + static final String NAME = "java/lang/invoke/RedefineTest$T"; + + static Class getClass(int r) { + byte[] classFile = getClassFile(r); + return UNSAFE.defineClass(NAME, classFile, 0, classFile.length, null, null); + } + + /** + * Generates a class of the following shape: + * static class T { + * @DontInline public static int f() { return $r; } + * } + */ + static byte[] getClassFile(int r) { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + MethodVisitor mv; + cw.visit(52, ACC_PUBLIC | ACC_SUPER, NAME, null, "java/lang/Object", null); + { + mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f", "()I", null, null); + mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true); + mv.visitCode(); + mv.visitLdcInsn(r); + mv.visitInsn(IRETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + static final MethodHandle mh; + static final Class CLS = getClass(0); + static { + try { + mh = LOOKUP.findStatic(CLS, "f", MethodType.methodType(int.class)); + } catch (Exception e) { + throw new Error(e); + } + } + + static final WhiteBox WB = WhiteBox.getWhiteBox(); + + @DontInline + static int invokeBasic() { + try { + return (int)mh.invokeExact(); + } catch (Throwable e) { + throw new Error(e); + } + } + + static Instrumentation instr; + public static void premain(String args, Instrumentation instr) { + RedefineTest.instr = instr; + } + + + public static void main(String[] args) throws Exception { + for (int i = 0; i < 20_000; i++) { + int r = invokeBasic(); + if (r != 0) { + throw new Error(r + " != 0"); + } + } + // WB.ensureCompiled(); + + redefine(); + + int exp = (instr != null) ? 1 : 0; + + for (int i = 0; i < 20_000; i++) { + if (invokeBasic() != exp) { + throw new Error(); + } + } + + WB.clearInlineCaches(); + + for (int i = 0; i < 20_000; i++) { + if (invokeBasic() != exp) { + throw new Error(); + } + } + + // WB.ensureCompiled(); + } + + static void redefine() { + if (instr == null) { + System.out.println("NOT REDEFINED"); + return; + } + ClassDefinition cd = new ClassDefinition(CLS, getClassFile(1)); + try { + instr.redefineClasses(cd); + } catch (Exception e) { + throw new Error(e); + } + System.out.println("REDEFINED"); + } +} diff --git a/hotspot/test/sanity/MismatchedWhiteBox/WhiteBox.java b/hotspot/test/sanity/MismatchedWhiteBox/WhiteBox.java index 8841c1362ab..87d56e442cb 100644 --- a/hotspot/test/sanity/MismatchedWhiteBox/WhiteBox.java +++ b/hotspot/test/sanity/MismatchedWhiteBox/WhiteBox.java @@ -29,7 +29,7 @@ * @library /testlibrary * @compile WhiteBox.java * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-CheckIntrinsics sun.hotspot.WhiteBox */ package sun.hotspot; From 7caf70643cacf9b6683dbb6b521f943434ce3c92 Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Fri, 4 Dec 2015 13:36:10 -0800 Subject: [PATCH 026/215] 8144657: Invalid format specifiers in jvmci trace messages Reviewed-by: kvn --- hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp b/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp index c50844963d0..50431ccca89 100644 --- a/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/jvmciCodeInstaller_sparc.cpp @@ -73,7 +73,7 @@ void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, T NativeMovConstReg32* move = nativeMovConstReg32_at(pc); narrowKlass narrowOop = record_narrow_metadata_reference(constant, CHECK); move->set_data((intptr_t)narrowOop); - TRACE_jvmci_3("relocating (narrow metaspace constant) at %p/%p", pc, narrowOop); + TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/0x%x", p2i(pc), narrowOop); #else JVMCI_ERROR("compressed Klass* on 32bit"); #endif @@ -81,7 +81,7 @@ void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, T NativeMovConstReg* move = nativeMovConstReg_at(pc); Metadata* reference = record_metadata_reference(constant, CHECK); move->set_data((intptr_t)reference); - TRACE_jvmci_3("relocating (metaspace constant) at %p/%p", pc, reference); + TRACE_jvmci_3("relocating (metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(reference)); } } From b5691de477939a174faa904adb7e10867d8d563b Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Fri, 4 Dec 2015 15:08:49 -0800 Subject: [PATCH 027/215] 8144748: Move assembler/macroAssembler inline function definitions to corresponding inline.hpp files Reviewed-by: kvn, coleenp --- hotspot/src/cpu/sparc/vm/assembler_sparc.hpp | 421 +++++++++--------- .../cpu/sparc/vm/assembler_sparc.inline.hpp | 303 +++++++++++++ .../src/cpu/sparc/vm/macroAssembler_sparc.cpp | 13 - .../src/cpu/sparc/vm/macroAssembler_sparc.hpp | 120 ++--- .../sparc/vm/macroAssembler_sparc.inline.hpp | 109 +++++ 5 files changed, 659 insertions(+), 307 deletions(-) diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp index 7c9c86a1466..ec1a2423aa0 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp @@ -677,11 +677,8 @@ class Assembler : public AbstractAssembler { protected: // Insert a nop if the previous is cbcond - void insert_nop_after_cbcond() { - if (UseCBCond && cbcond_before()) { - nop(); - } - } + inline void insert_nop_after_cbcond(); + // Delay slot helpers // cti is called when emitting control-transfer instruction, // BEFORE doing the emitting. @@ -739,7 +736,7 @@ public: } inline void emit_int32(int); // shadows AbstractAssembler::emit_int32 - inline void emit_data(int x) { emit_int32(x); } + inline void emit_data(int x); inline void emit_data(int, RelocationHolder const&); inline void emit_data(int, relocInfo::relocType rtype); // helper for above fcns @@ -754,31 +751,31 @@ public: inline void add(Register s1, Register s2, Register d ); inline void add(Register s1, int simm13a, Register d ); - void addcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void addcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void addc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 ) | rs1(s1) | rs2(s2) ); } - void addc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void addccc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void addccc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void addcc( Register s1, Register s2, Register d ); + inline void addcc( Register s1, int simm13a, Register d ); + inline void addc( Register s1, Register s2, Register d ); + inline void addc( Register s1, int simm13a, Register d ); + inline void addccc( Register s1, Register s2, Register d ); + inline void addccc( Register s1, int simm13a, Register d ); // 4-operand AES instructions - void aes_eround01( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround01_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_eround23( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround23_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_dround01( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround01_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_dround23( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround23_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_eround01_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround01_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_eround23_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround23_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_dround01_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround01_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_dround23_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround23_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_kexpand1( FloatRegister s1, FloatRegister s2, int imm5a, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | u_field(imm5a, 13, 9) | op5(aes_kexpand1_op5) | fs2(s2, FloatRegisterImpl::D) ); } + inline void aes_eround01( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_eround23( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_dround01( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_dround23( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_eround01_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_eround23_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_dround01_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_dround23_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ); + inline void aes_kexpand1( FloatRegister s1, FloatRegister s2, int imm5a, FloatRegister d ); // 3-operand AES instructions - void aes_kexpand0( FloatRegister s1, FloatRegister s2, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes3_op3) | fs1(s1, FloatRegisterImpl::D) | opf(aes_kexpand0_opf) | fs2(s2, FloatRegisterImpl::D) ); } - void aes_kexpand2( FloatRegister s1, FloatRegister s2, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes3_op3) | fs1(s1, FloatRegisterImpl::D) | opf(aes_kexpand2_opf) | fs2(s2, FloatRegisterImpl::D) ); } + inline void aes_kexpand0( FloatRegister s1, FloatRegister s2, FloatRegister d ); + inline void aes_kexpand2( FloatRegister s1, FloatRegister s2, FloatRegister d ); // pp 136 @@ -827,70 +824,70 @@ public: // at address s1 is swapped with the data in d. If the values are not equal, // the the contents of memory at s1 is loaded into d, without the swap. - void casa( Register s1, Register s2, Register d, int ia = -1 ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(casa_op3 ) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); } - void casxa( Register s1, Register s2, Register d, int ia = -1 ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(casxa_op3) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); } + inline void casa( Register s1, Register s2, Register d, int ia = -1 ); + inline void casxa( Register s1, Register s2, Register d, int ia = -1 ); // pp 152 - void udiv( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 ) | rs1(s1) | rs2(s2)); } - void udiv( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void sdiv( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 ) | rs1(s1) | rs2(s2)); } - void sdiv( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void udivcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); } - void udivcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void sdivcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); } - void sdivcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void udiv( Register s1, Register s2, Register d ); + inline void udiv( Register s1, int simm13a, Register d ); + inline void sdiv( Register s1, Register s2, Register d ); + inline void sdiv( Register s1, int simm13a, Register d ); + inline void udivcc( Register s1, Register s2, Register d ); + inline void udivcc( Register s1, int simm13a, Register d ); + inline void sdivcc( Register s1, Register s2, Register d ); + inline void sdivcc( Register s1, int simm13a, Register d ); // pp 155 - void done() { v9_only(); cti(); emit_int32( op(arith_op) | fcn(0) | op3(done_op3) ); } - void retry() { v9_only(); cti(); emit_int32( op(arith_op) | fcn(1) | op3(retry_op3) ); } + inline void done(); + inline void retry(); // pp 156 - void fadd( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x40 + w) | fs2(s2, w)); } - void fsub( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x44 + w) | fs2(s2, w)); } + inline void fadd( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ); + inline void fsub( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ); // pp 157 - void fcmp( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { emit_int32( op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x50 + w) | fs2(s2, w)); } - void fcmpe( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { emit_int32( op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x54 + w) | fs2(s2, w)); } + inline void fcmp( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2); + inline void fcmpe( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2); // pp 159 - void ftox( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(fpop1_op3) | opf(0x80 + w) | fs2(s, w)); } - void ftoi( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(fpop1_op3) | opf(0xd0 + w) | fs2(s, w)); } + inline void ftox( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); + inline void ftoi( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); // pp 160 - void ftof( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, dw) | op3(fpop1_op3) | opf(0xc0 + sw + dw*4) | fs2(s, sw)); } + inline void ftof( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s, FloatRegister d ); // pp 161 - void fxtof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x80 + w*4) | fs2(s, FloatRegisterImpl::D)); } - void fitof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0xc0 + w*4) | fs2(s, FloatRegisterImpl::S)); } + inline void fxtof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); + inline void fitof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); // pp 162 - void fmov( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x00 + w) | fs2(s, w)); } + inline void fmov( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); - void fneg( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x04 + w) | fs2(s, w)); } + inline void fneg( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); - void fabs( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x08 + w) | fs2(s, w)); } + inline void fabs( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); // pp 163 - void fmul( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x48 + w) | fs2(s2, w)); } - void fmul( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, dw) | op3(fpop1_op3) | fs1(s1, sw) | opf(0x60 + sw + dw*4) | fs2(s2, sw)); } - void fdiv( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x4c + w) | fs2(s2, w)); } + inline void fmul( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ); + inline void fmul( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s1, FloatRegister s2, FloatRegister d ); + inline void fdiv( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ); // FXORs/FXORd instructions - void fxor( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(flog3_op3) | fs1(s1, w) | opf(0x6E - w) | fs2(s2, w)); } + inline void fxor( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ); // pp 164 - void fsqrt( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x28 + w) | fs2(s, w)); } + inline void fsqrt( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ); // pp 165 @@ -899,17 +896,17 @@ public: // pp 167 - void flushw() { v9_only(); emit_int32( op(arith_op) | op3(flushw_op3) ); } + void flushw(); // pp 168 - void illtrap( int const22a) { if (const22a != 0) v9_only(); emit_int32( op(branch_op) | u_field(const22a, 21, 0) ); } + void illtrap( int const22a); // v8 unimp == illtrap(0) // pp 169 - void impdep1( int id1, int const19a ) { v9_only(); emit_int32( op(arith_op) | fcn(id1) | op3(impdep1_op3) | u_field(const19a, 18, 0)); } - void impdep2( int id1, int const19a ) { v9_only(); emit_int32( op(arith_op) | fcn(id1) | op3(impdep2_op3) | u_field(const19a, 18, 0)); } + void impdep1( int id1, int const19a ); + void impdep2( int id1, int const19a ); // pp 170 @@ -929,8 +926,8 @@ public: // 173 - void ldfa( FloatRegisterImpl::Width w, Register s1, Register s2, int ia, FloatRegister d ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void ldfa( FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void ldfa( FloatRegisterImpl::Width w, Register s1, Register s2, int ia, FloatRegister d ); + inline void ldfa( FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d ); // pp 175, lduw is ld on v8 @@ -953,119 +950,119 @@ public: // pp 177 - void ldsba( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void ldsba( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void ldsha( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void ldsha( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void ldswa( Register s1, Register s2, int ia, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void ldswa( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void lduba( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void lduba( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void lduha( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void lduha( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void lduwa( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void lduwa( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void ldxa( Register s1, Register s2, int ia, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void ldxa( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void ldsba( Register s1, Register s2, int ia, Register d ); + inline void ldsba( Register s1, int simm13a, Register d ); + inline void ldsha( Register s1, Register s2, int ia, Register d ); + inline void ldsha( Register s1, int simm13a, Register d ); + inline void ldswa( Register s1, Register s2, int ia, Register d ); + inline void ldswa( Register s1, int simm13a, Register d ); + inline void lduba( Register s1, Register s2, int ia, Register d ); + inline void lduba( Register s1, int simm13a, Register d ); + inline void lduha( Register s1, Register s2, int ia, Register d ); + inline void lduha( Register s1, int simm13a, Register d ); + inline void lduwa( Register s1, Register s2, int ia, Register d ); + inline void lduwa( Register s1, int simm13a, Register d ); + inline void ldxa( Register s1, Register s2, int ia, Register d ); + inline void ldxa( Register s1, int simm13a, Register d ); // pp 181 - void and3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 ) | rs1(s1) | rs2(s2) ); } - void and3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void andcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void andcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void andn( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 ) | rs1(s1) | rs2(s2) ); } - void andn( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void andncc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void andncc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void or3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 ) | rs1(s1) | rs2(s2) ); } - void or3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void orcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void orcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void orn( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | rs2(s2) ); } - void orn( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void orncc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void orncc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void xor3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 ) | rs1(s1) | rs2(s2) ); } - void xor3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void xorcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void xorcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void xnor( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 ) | rs1(s1) | rs2(s2) ); } - void xnor( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void xnorcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void xnorcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void and3( Register s1, Register s2, Register d ); + inline void and3( Register s1, int simm13a, Register d ); + inline void andcc( Register s1, Register s2, Register d ); + inline void andcc( Register s1, int simm13a, Register d ); + inline void andn( Register s1, Register s2, Register d ); + inline void andn( Register s1, int simm13a, Register d ); + inline void andncc( Register s1, Register s2, Register d ); + inline void andncc( Register s1, int simm13a, Register d ); + inline void or3( Register s1, Register s2, Register d ); + inline void or3( Register s1, int simm13a, Register d ); + inline void orcc( Register s1, Register s2, Register d ); + inline void orcc( Register s1, int simm13a, Register d ); + inline void orn( Register s1, Register s2, Register d ); + inline void orn( Register s1, int simm13a, Register d ); + inline void orncc( Register s1, Register s2, Register d ); + inline void orncc( Register s1, int simm13a, Register d ); + inline void xor3( Register s1, Register s2, Register d ); + inline void xor3( Register s1, int simm13a, Register d ); + inline void xorcc( Register s1, Register s2, Register d ); + inline void xorcc( Register s1, int simm13a, Register d ); + inline void xnor( Register s1, Register s2, Register d ); + inline void xnor( Register s1, int simm13a, Register d ); + inline void xnorcc( Register s1, Register s2, Register d ); + inline void xnorcc( Register s1, int simm13a, Register d ); // pp 183 - void membar( Membar_mask_bits const7a ) { v9_only(); emit_int32( op(arith_op) | op3(membar_op3) | rs1(O7) | immed(true) | u_field( int(const7a), 6, 0)); } + inline void membar( Membar_mask_bits const7a ); // pp 185 - void fmov( FloatRegisterImpl::Width w, Condition c, bool floatCC, CC cca, FloatRegister s2, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop2_op3) | cond_mov(c) | opf_cc(cca, floatCC) | opf_low6(w) | fs2(s2, w)); } + inline void fmov( FloatRegisterImpl::Width w, Condition c, bool floatCC, CC cca, FloatRegister s2, FloatRegister d ); // pp 189 - void fmov( FloatRegisterImpl::Width w, RCondition c, Register s1, FloatRegister s2, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop2_op3) | rs1(s1) | rcond(c) | opf_low5(4 + w) | fs2(s2, w)); } + inline void fmov( FloatRegisterImpl::Width w, RCondition c, Register s1, FloatRegister s2, FloatRegister d ); // pp 191 - void movcc( Condition c, bool floatCC, CC cca, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | rs2(s2) ); } - void movcc( Condition c, bool floatCC, CC cca, int simm11a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | immed(true) | simm(simm11a, 11) ); } + inline void movcc( Condition c, bool floatCC, CC cca, Register s2, Register d ); + inline void movcc( Condition c, bool floatCC, CC cca, int simm11a, Register d ); // pp 195 - void movr( RCondition c, Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | rs2(s2) ); } - void movr( RCondition c, Register s1, int simm10a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | immed(true) | simm(simm10a, 10) ); } + inline void movr( RCondition c, Register s1, Register s2, Register d ); + inline void movr( RCondition c, Register s1, int simm10a, Register d ); // pp 196 - void mulx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(mulx_op3 ) | rs1(s1) | rs2(s2) ); } - void mulx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(mulx_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void sdivx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | rs2(s2) ); } - void sdivx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void udivx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | rs2(s2) ); } - void udivx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void mulx( Register s1, Register s2, Register d ); + inline void mulx( Register s1, int simm13a, Register d ); + inline void sdivx( Register s1, Register s2, Register d ); + inline void sdivx( Register s1, int simm13a, Register d ); + inline void udivx( Register s1, Register s2, Register d ); + inline void udivx( Register s1, int simm13a, Register d ); // pp 197 - void umul( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 ) | rs1(s1) | rs2(s2) ); } - void umul( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void smul( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 ) | rs1(s1) | rs2(s2) ); } - void smul( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void umulcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void umulcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void smulcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void smulcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void umul( Register s1, Register s2, Register d ); + inline void umul( Register s1, int simm13a, Register d ); + inline void smul( Register s1, Register s2, Register d ); + inline void smul( Register s1, int simm13a, Register d ); + inline void umulcc( Register s1, Register s2, Register d ); + inline void umulcc( Register s1, int simm13a, Register d ); + inline void smulcc( Register s1, Register s2, Register d ); + inline void smulcc( Register s1, int simm13a, Register d ); // pp 201 - void nop() { emit_int32( op(branch_op) | op2(sethi_op2) ); } + inline void nop(); - void sw_count() { emit_int32( op(branch_op) | op2(sethi_op2) | 0x3f0 ); } + inline void sw_count(); // pp 202 - void popc( Register s, Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(popc_op3) | rs2(s)); } - void popc( int simm13a, Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(popc_op3) | immed(true) | simm(simm13a, 13)); } + inline void popc( Register s, Register d); + inline void popc( int simm13a, Register d); // pp 203 - void prefetch( Register s1, Register s2, PrefetchFcn f) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | rs2(s2) ); } - void prefetch( Register s1, int simm13a, PrefetchFcn f) { v9_only(); emit_data( op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } + inline void prefetch( Register s1, Register s2, PrefetchFcn f); + inline void prefetch( Register s1, int simm13a, PrefetchFcn f); - void prefetcha( Register s1, Register s2, int ia, PrefetchFcn f ) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void prefetcha( Register s1, int simm13a, PrefetchFcn f ) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void prefetcha( Register s1, Register s2, int ia, PrefetchFcn f ); + inline void prefetcha( Register s1, int simm13a, PrefetchFcn f ); // pp 208 // not implementing read privileged register - inline void rdy( Register d) { v9_dep(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(0, 18, 14)); } - inline void rdccr( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(2, 18, 14)); } - inline void rdasi( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(3, 18, 14)); } - inline void rdtick( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(4, 18, 14)); } // Spoon! - inline void rdpc( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(5, 18, 14)); } - inline void rdfprs( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(6, 18, 14)); } + inline void rdy( Register d); + inline void rdccr( Register d); + inline void rdasi( Register d); + inline void rdtick( Register d); + inline void rdpc( Register d); + inline void rdfprs( Register d); // pp 213 @@ -1074,47 +1071,43 @@ public: // pp 214 - void save( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | rs2(s2) ); } - void save( Register s1, int simm13a, Register d ) { - // make sure frame is at least large enough for the register save area - assert(-simm13a >= 16 * wordSize, "frame too small"); - emit_int32( op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); - } + inline void save( Register s1, Register s2, Register d ); + inline void save( Register s1, int simm13a, Register d ); - void restore( Register s1 = G0, Register s2 = G0, Register d = G0 ) { emit_int32( op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | rs2(s2) ); } - void restore( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void restore( Register s1 = G0, Register s2 = G0, Register d = G0 ); + inline void restore( Register s1, int simm13a, Register d ); // pp 216 - void saved() { v9_only(); emit_int32( op(arith_op) | fcn(0) | op3(saved_op3)); } - void restored() { v9_only(); emit_int32( op(arith_op) | fcn(1) | op3(saved_op3)); } + inline void saved(); + inline void restored(); // pp 217 inline void sethi( int imm22a, Register d, RelocationHolder const& rspec = RelocationHolder() ); // pp 218 - void sll( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | rs2(s2) ); } - void sll( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); } - void srl( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | rs2(s2) ); } - void srl( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); } - void sra( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | rs2(s2) ); } - void sra( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); } + inline void sll( Register s1, Register s2, Register d ); + inline void sll( Register s1, int imm5a, Register d ); + inline void srl( Register s1, Register s2, Register d ); + inline void srl( Register s1, int imm5a, Register d ); + inline void sra( Register s1, Register s2, Register d ); + inline void sra( Register s1, int imm5a, Register d ); - void sllx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | rs2(s2) ); } - void sllx( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); } - void srlx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | rs2(s2) ); } - void srlx( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); } - void srax( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | rs2(s2) ); } - void srax( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); } + inline void sllx( Register s1, Register s2, Register d ); + inline void sllx( Register s1, int imm6a, Register d ); + inline void srlx( Register s1, Register s2, Register d ); + inline void srlx( Register s1, int imm6a, Register d ); + inline void srax( Register s1, Register s2, Register d ); + inline void srax( Register s1, int imm6a, Register d ); // pp 220 - void sir( int simm13a ) { emit_int32( op(arith_op) | fcn(15) | op3(sir_op3) | immed(true) | simm(simm13a, 13)); } + inline void sir( int simm13a ); // pp 221 - void stbar() { emit_int32( op(arith_op) | op3(membar_op3) | u_field(15, 18, 14)); } + inline void stbar(); // pp 222 @@ -1128,8 +1121,8 @@ public: // pp 224 - void stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2, int ia ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2, int ia ); + inline void stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a ); // p 226 @@ -1146,28 +1139,28 @@ public: // pp 177 - void stba( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void stba( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void stha( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void stha( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void stwa( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void stwa( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void stxa( Register d, Register s1, Register s2, int ia ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void stxa( Register d, Register s1, int simm13a ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void stda( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void stda( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void stba( Register d, Register s1, Register s2, int ia ); + inline void stba( Register d, Register s1, int simm13a ); + inline void stha( Register d, Register s1, Register s2, int ia ); + inline void stha( Register d, Register s1, int simm13a ); + inline void stwa( Register d, Register s1, Register s2, int ia ); + inline void stwa( Register d, Register s1, int simm13a ); + inline void stxa( Register d, Register s1, Register s2, int ia ); + inline void stxa( Register d, Register s1, int simm13a ); + inline void stda( Register d, Register s1, Register s2, int ia ); + inline void stda( Register d, Register s1, int simm13a ); // pp 230 - void sub( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | rs2(s2) ); } - void sub( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void sub( Register s1, Register s2, Register d ); + inline void sub( Register s1, int simm13a, Register d ); - void subcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | rs2(s2) ); } - void subcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void subc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | rs2(s2) ); } - void subc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } - void subccc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } - void subccc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void subcc( Register s1, Register s2, Register d ); + inline void subcc( Register s1, int simm13a, Register d ); + inline void subc( Register s1, Register s2, Register d ); + inline void subc( Register s1, int simm13a, Register d ); + inline void subccc( Register s1, Register s2, Register d ); + inline void subccc( Register s1, int simm13a, Register d ); // pp 231 @@ -1176,86 +1169,80 @@ public: // pp 232 - void swapa( Register s1, Register s2, int ia, Register d ) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } - void swapa( Register s1, int simm13a, Register d ) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void swapa( Register s1, Register s2, int ia, Register d ); + inline void swapa( Register s1, int simm13a, Register d ); // pp 234, note op in book is wrong, see pp 268 - void taddcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(taddcc_op3 ) | rs1(s1) | rs2(s2) ); } - void taddcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(taddcc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void taddcc( Register s1, Register s2, Register d ); + inline void taddcc( Register s1, int simm13a, Register d ); // pp 235 - void tsubcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(tsubcc_op3 ) | rs1(s1) | rs2(s2) ); } - void tsubcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(tsubcc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void tsubcc( Register s1, Register s2, Register d ); + inline void tsubcc( Register s1, int simm13a, Register d ); // pp 237 - void trap( Condition c, CC cc, Register s1, Register s2 ) { emit_int32( op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | rs2(s2)); } - void trap( Condition c, CC cc, Register s1, int trapa ) { emit_int32( op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | immed(true) | u_field(trapa, 6, 0)); } + inline void trap( Condition c, CC cc, Register s1, Register s2 ); + inline void trap( Condition c, CC cc, Register s1, int trapa ); // simple uncond. trap - void trap( int trapa ) { trap( always, icc, G0, trapa ); } + inline void trap( int trapa ); // pp 239 omit write priv register for now - inline void wry( Register d) { v9_dep(); emit_int32( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(0, 29, 25)); } - inline void wrccr(Register s) { v9_only(); emit_int32( op(arith_op) | rs1(s) | op3(wrreg_op3) | u_field(2, 29, 25)); } - inline void wrccr(Register s, int simm13a) { v9_only(); emit_int32( op(arith_op) | - rs1(s) | - op3(wrreg_op3) | - u_field(2, 29, 25) | - immed(true) | - simm(simm13a, 13)); } - inline void wrasi(Register d) { v9_only(); emit_int32( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25)); } + inline void wry( Register d); + inline void wrccr(Register s); + inline void wrccr(Register s, int simm13a); + inline void wrasi(Register d); // wrasi(d, imm) stores (d xor imm) to asi - inline void wrasi(Register d, int simm13a) { v9_only(); emit_int32( op(arith_op) | rs1(d) | op3(wrreg_op3) | - u_field(3, 29, 25) | immed(true) | simm(simm13a, 13)); } - inline void wrfprs( Register d) { v9_only(); emit_int32( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(6, 29, 25)); } + inline void wrasi(Register d, int simm13a); + inline void wrfprs( Register d); // VIS1 instructions - void alignaddr( Register s1, Register s2, Register d ) { vis1_only(); emit_int32( op(arith_op) | rd(d) | op3(alignaddr_op3) | rs1(s1) | opf(alignaddr_opf) | rs2(s2)); } + inline void alignaddr( Register s1, Register s2, Register d ); - void faligndata( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(faligndata_op3) | fs1(s1, FloatRegisterImpl::D) | opf(faligndata_opf) | fs2(s2, FloatRegisterImpl::D)); } + inline void faligndata( FloatRegister s1, FloatRegister s2, FloatRegister d ); - void fzero( FloatRegisterImpl::Width w, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fzero_op3) | opf(0x62 - w)); } + inline void fzero( FloatRegisterImpl::Width w, FloatRegister d ); - void fsrc2( FloatRegisterImpl::Width w, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fsrc_op3) | opf(0x7A - w) | fs2(s2, w)); } + inline void fsrc2( FloatRegisterImpl::Width w, FloatRegister s2, FloatRegister d ); - void fnot1( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fnot_op3) | fs1(s1, w) | opf(0x6C - w)); } + inline void fnot1( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister d ); - void fpmerge( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(0x36) | fs1(s1, FloatRegisterImpl::S) | opf(0x4b) | fs2(s2, FloatRegisterImpl::S)); } + inline void fpmerge( FloatRegister s1, FloatRegister s2, FloatRegister d ); - void stpartialf( Register s1, Register s2, FloatRegister d, int ia = -1 ) { vis1_only(); emit_int32( op(ldst_op) | fd(d, FloatRegisterImpl::D) | op3(stpartialf_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); } + inline void stpartialf( Register s1, Register s2, FloatRegister d, int ia = -1 ); // VIS2 instructions - void edge8n( Register s1, Register s2, Register d ) { vis2_only(); emit_int32( op(arith_op) | rd(d) | op3(edge_op3) | rs1(s1) | opf(edge8n_opf) | rs2(s2)); } + inline void edge8n( Register s1, Register s2, Register d ); - void bmask( Register s1, Register s2, Register d ) { vis2_only(); emit_int32( op(arith_op) | rd(d) | op3(bmask_op3) | rs1(s1) | opf(bmask_opf) | rs2(s2)); } - void bshuffle( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis2_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(bshuffle_op3) | fs1(s1, FloatRegisterImpl::D) | opf(bshuffle_opf) | fs2(s2, FloatRegisterImpl::D)); } + inline void bmask( Register s1, Register s2, Register d ); + inline void bshuffle( FloatRegister s1, FloatRegister s2, FloatRegister d ); // VIS3 instructions - void movstosw( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstosw_opf) | fs2(s, FloatRegisterImpl::S)); } - void movstouw( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstouw_opf) | fs2(s, FloatRegisterImpl::S)); } - void movdtox( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mdtox_opf) | fs2(s, FloatRegisterImpl::D)); } + inline void movstosw( FloatRegister s, Register d ); + inline void movstouw( FloatRegister s, Register d ); + inline void movdtox( FloatRegister s, Register d ); - void movwtos( Register s, FloatRegister d ) { vis3_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(mftoi_op3) | opf(mwtos_opf) | rs2(s)); } - void movxtod( Register s, FloatRegister d ) { vis3_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(mftoi_op3) | opf(mxtod_opf) | rs2(s)); } + inline void movwtos( Register s, FloatRegister d ); + inline void movxtod( Register s, FloatRegister d ); - void xmulx(Register s1, Register s2, Register d) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulx_opf) | rs2(s2)); } - void xmulxhi(Register s1, Register s2, Register d) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulxhi_opf) | rs2(s2)); } + inline void xmulx(Register s1, Register s2, Register d); + inline void xmulxhi(Register s1, Register s2, Register d); // Crypto SHA instructions - void sha1() { sha1_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha1_opf)); } - void sha256() { sha256_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha256_opf)); } - void sha512() { sha512_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha512_opf)); } + inline void sha1(); + inline void sha256(); + inline void sha512(); // CRC32C instruction - void crc32c( FloatRegister s1, FloatRegister s2, FloatRegister d ) { crc32c_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(crc32c_op3) | fs1(s1, FloatRegisterImpl::D) | opf(crc32c_opf) | fs2(s2, FloatRegisterImpl::D)); } + inline void crc32c( FloatRegister s1, FloatRegister s2, FloatRegister d ); // Creation Assembler(CodeBuffer* code) : AbstractAssembler(code) { diff --git a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp index 197e26fa6f8..c18b07ec019 100644 --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp @@ -28,6 +28,12 @@ #include "asm/assembler.hpp" +inline void Assembler::insert_nop_after_cbcond() { + if (UseCBCond && cbcond_before()) { + nop(); + } +} + inline void Assembler::check_delay() { # ifdef CHECK_DELAY guarantee( delay_state != at_delay_slot, "must say delayed() when filling delay slot"); @@ -40,6 +46,10 @@ inline void Assembler::emit_int32(int x) { AbstractAssembler::emit_int32(x); } +inline void Assembler::emit_data(int x) { + emit_int32(x); +} + inline void Assembler::emit_data(int x, relocInfo::relocType rtype) { relocate(rtype); emit_int32(x); @@ -54,6 +64,29 @@ inline void Assembler::emit_data(int x, RelocationHolder const& rspec) { inline void Assembler::add(Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::add(Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::addcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::addcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::addc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::addc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::addccc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::addccc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::aes_eround01( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround01_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_eround23( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround23_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_dround01( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround01_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_dround23( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround23_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_eround01_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround01_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_eround23_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_eround23_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_dround01_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround01_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_dround23_l( FloatRegister s1, FloatRegister s2, FloatRegister s3, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | fs3(s3, FloatRegisterImpl::D) | op5(aes_dround23_l_op5) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_kexpand1( FloatRegister s1, FloatRegister s2, int imm5a, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes4_op3) | fs1(s1, FloatRegisterImpl::D) | u_field(imm5a, 13, 9) | op5(aes_kexpand1_op5) | fs2(s2, FloatRegisterImpl::D) ); } + + +// 3-operand AES instructions + +inline void Assembler::aes_kexpand0( FloatRegister s1, FloatRegister s2, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes3_op3) | fs1(s1, FloatRegisterImpl::D) | opf(aes_kexpand0_opf) | fs2(s2, FloatRegisterImpl::D) ); } +inline void Assembler::aes_kexpand2( FloatRegister s1, FloatRegister s2, FloatRegister d ) { aes_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(aes3_op3) | fs1(s1, FloatRegisterImpl::D) | opf(aes_kexpand2_opf) | fs2(s2, FloatRegisterImpl::D) ); } + inline void Assembler::bpr( RCondition c, bool a, Predict p, Register s1, address d, relocInfo::relocType rt ) { v9_only(); insert_nop_after_cbcond(); cti(); emit_data( op(branch_op) | annul(a) | cond(c) | op2(bpr_op2) | wdisp16(intptr_t(d), intptr_t(pc())) | predict(p) | rs1(s1), rt); has_delay_slot(); } inline void Assembler::bpr( RCondition c, bool a, Predict p, Register s1, Label& L) { insert_nop_after_cbcond(); bpr( c, a, p, s1, target(L)); } @@ -78,9 +111,56 @@ inline void Assembler::call( Label& L, relocInfo::relocType rt ) { insert_nop_ inline void Assembler::call( address d, RelocationHolder const& rspec ) { insert_nop_after_cbcond(); cti(); emit_data( op(call_op) | wdisp(intptr_t(d), intptr_t(pc()), 30), rspec); has_delay_slot(); assert(rspec.type() != relocInfo::virtual_call_type, "must use virtual_call_Relocation::spec"); } +inline void Assembler::casa( Register s1, Register s2, Register d, int ia ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(casa_op3 ) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); } +inline void Assembler::casxa( Register s1, Register s2, Register d, int ia ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(casxa_op3) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); } + +inline void Assembler::udiv( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 ) | rs1(s1) | rs2(s2)); } +inline void Assembler::udiv( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::sdiv( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 ) | rs1(s1) | rs2(s2)); } +inline void Assembler::sdiv( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::udivcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); } +inline void Assembler::udivcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::sdivcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); } +inline void Assembler::sdivcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::done() { v9_only(); cti(); emit_int32( op(arith_op) | fcn(0) | op3(done_op3) ); } +inline void Assembler::retry() { v9_only(); cti(); emit_int32( op(arith_op) | fcn(1) | op3(retry_op3) ); } + +inline void Assembler::fadd( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x40 + w) | fs2(s2, w)); } +inline void Assembler::fsub( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x44 + w) | fs2(s2, w)); } + +inline void Assembler::fcmp( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { emit_int32( op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x50 + w) | fs2(s2, w)); } +inline void Assembler::fcmpe( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { emit_int32( op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x54 + w) | fs2(s2, w)); } + +inline void Assembler::ftox( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(fpop1_op3) | opf(0x80 + w) | fs2(s, w)); } +inline void Assembler::ftoi( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(fpop1_op3) | opf(0xd0 + w) | fs2(s, w)); } + +inline void Assembler::ftof( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, dw) | op3(fpop1_op3) | opf(0xc0 + sw + dw*4) | fs2(s, sw)); } + +inline void Assembler::fxtof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x80 + w*4) | fs2(s, FloatRegisterImpl::D)); } +inline void Assembler::fitof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0xc0 + w*4) | fs2(s, FloatRegisterImpl::S)); } + +inline void Assembler::fmov( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x00 + w) | fs2(s, w)); } +inline void Assembler::fneg( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x04 + w) | fs2(s, w)); } +inline void Assembler::fabs( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x08 + w) | fs2(s, w)); } +inline void Assembler::fmul( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x48 + w) | fs2(s2, w)); } +inline void Assembler::fmul( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, dw) | op3(fpop1_op3) | fs1(s1, sw) | opf(0x60 + sw + dw*4) | fs2(s2, sw)); } +inline void Assembler::fdiv( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x4c + w) | fs2(s2, w)); } + +inline void Assembler::fxor( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(flog3_op3) | fs1(s1, w) | opf(0x6E - w) | fs2(s2, w)); } + +inline void Assembler::fsqrt( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x28 + w) | fs2(s, w)); } + inline void Assembler::flush( Register s1, Register s2) { emit_int32( op(arith_op) | op3(flush_op3) | rs1(s1) | rs2(s2)); } inline void Assembler::flush( Register s1, int simm13a) { emit_data( op(arith_op) | op3(flush_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::flushw() { v9_only(); emit_int32( op(arith_op) | op3(flushw_op3) ); } + +inline void Assembler::illtrap( int const22a) { if (const22a != 0) v9_only(); emit_int32( op(branch_op) | u_field(const22a, 21, 0) ); } + +inline void Assembler::impdep1( int id1, int const19a ) { v9_only(); emit_int32( op(arith_op) | fcn(id1) | op3(impdep1_op3) | u_field(const19a, 18, 0)); } +inline void Assembler::impdep2( int id1, int const19a ) { v9_only(); emit_int32( op(arith_op) | fcn(id1) | op3(impdep2_op3) | u_field(const19a, 18, 0)); } + inline void Assembler::jmpl( Register s1, Register s2, Register d ) { insert_nop_after_cbcond(); cti(); emit_int32( op(arith_op) | rd(d) | op3(jmpl_op3) | rs1(s1) | rs2(s2)); has_delay_slot(); } inline void Assembler::jmpl( Register s1, int simm13a, Register d, RelocationHolder const& rspec ) { insert_nop_after_cbcond(); cti(); emit_data( op(arith_op) | rd(d) | op3(jmpl_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec); has_delay_slot(); } @@ -90,6 +170,9 @@ inline void Assembler::ldf(FloatRegisterImpl::Width w, Register s1, int simm13a, inline void Assembler::ldxfsr( Register s1, Register s2) { v9_only(); emit_int32( op(ldst_op) | rd(G1) | op3(ldfsr_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::ldxfsr( Register s1, int simm13a) { v9_only(); emit_data( op(ldst_op) | rd(G1) | op3(ldfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::ldfa( FloatRegisterImpl::Width w, Register s1, Register s2, int ia, FloatRegister d ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::ldfa( FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + inline void Assembler::ldsb( Register s1, Register s2, Register d) { emit_int32( op(ldst_op) | rd(d) | op3(ldsb_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::ldsb( Register s1, int simm13a, Register d) { emit_data( op(ldst_op) | rd(d) | op3(ldsb_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } @@ -109,11 +192,134 @@ inline void Assembler::ldx( Register s1, int simm13a, Register d) { v9_only(); inline void Assembler::ldd( Register s1, Register s2, Register d) { v9_dep(); assert(d->is_even(), "not even"); emit_int32( op(ldst_op) | rd(d) | op3(ldd_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::ldd( Register s1, int simm13a, Register d) { v9_dep(); assert(d->is_even(), "not even"); emit_data( op(ldst_op) | rd(d) | op3(ldd_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::ldsba( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::ldsba( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::ldsha( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::ldsha( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::ldswa( Register s1, Register s2, int ia, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::ldswa( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::lduba( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::lduba( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::lduha( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::lduha( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::lduwa( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::lduwa( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::ldxa( Register s1, Register s2, int ia, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::ldxa( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::and3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::and3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::andcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::andcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::andn( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::andn( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::andncc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::andncc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::or3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::or3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::orcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::orcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::orn( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::orn( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::orncc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::orncc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::xor3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::xor3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::xorcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::xorcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::xnor( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::xnor( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::xnorcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::xnorcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::membar( Membar_mask_bits const7a ) { v9_only(); emit_int32( op(arith_op) | op3(membar_op3) | rs1(O7) | immed(true) | u_field( int(const7a), 6, 0)); } + +inline void Assembler::fmov( FloatRegisterImpl::Width w, Condition c, bool floatCC, CC cca, FloatRegister s2, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop2_op3) | cond_mov(c) | opf_cc(cca, floatCC) | opf_low6(w) | fs2(s2, w)); } + +inline void Assembler::fmov( FloatRegisterImpl::Width w, RCondition c, Register s1, FloatRegister s2, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop2_op3) | rs1(s1) | rcond(c) | opf_low5(4 + w) | fs2(s2, w)); } + +inline void Assembler::movcc( Condition c, bool floatCC, CC cca, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | rs2(s2) ); } +inline void Assembler::movcc( Condition c, bool floatCC, CC cca, int simm11a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | immed(true) | simm(simm11a, 11) ); } + +inline void Assembler::movr( RCondition c, Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | rs2(s2) ); } +inline void Assembler::movr( RCondition c, Register s1, int simm10a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | immed(true) | simm(simm10a, 10) ); } + +inline void Assembler::mulx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(mulx_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::mulx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(mulx_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::sdivx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::sdivx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::udivx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::udivx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::umul( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::umul( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::smul( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::smul( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::umulcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::umulcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::smulcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::smulcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::nop() { emit_int32( op(branch_op) | op2(sethi_op2) ); } + +inline void Assembler::sw_count() { emit_int32( op(branch_op) | op2(sethi_op2) | 0x3f0 ); } + +inline void Assembler::popc( Register s, Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(popc_op3) | rs2(s)); } +inline void Assembler::popc( int simm13a, Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(popc_op3) | immed(true) | simm(simm13a, 13)); } + +inline void Assembler::prefetch( Register s1, Register s2, PrefetchFcn f) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::prefetch( Register s1, int simm13a, PrefetchFcn f) { v9_only(); emit_data( op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } + +inline void Assembler::prefetcha( Register s1, Register s2, int ia, PrefetchFcn f ) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::prefetcha( Register s1, int simm13a, PrefetchFcn f ) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::rdy( Register d) { v9_dep(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(0, 18, 14)); } +inline void Assembler::rdccr( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(2, 18, 14)); } +inline void Assembler::rdasi( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(3, 18, 14)); } +inline void Assembler::rdtick( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(4, 18, 14)); } // Spoon! +inline void Assembler::rdpc( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(5, 18, 14)); } +inline void Assembler::rdfprs( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(6, 18, 14)); } + inline void Assembler::rett( Register s1, Register s2 ) { cti(); emit_int32( op(arith_op) | op3(rett_op3) | rs1(s1) | rs2(s2)); has_delay_slot(); } inline void Assembler::rett( Register s1, int simm13a, relocInfo::relocType rt) { cti(); emit_data( op(arith_op) | op3(rett_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rt); has_delay_slot(); } +inline void Assembler::save( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::save( Register s1, int simm13a, Register d ) { + // make sure frame is at least large enough for the register save area + assert(-simm13a >= 16 * wordSize, "frame too small"); + emit_int32( op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); +} + +inline void Assembler::restore( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::restore( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +// pp 216 + +inline void Assembler::saved() { v9_only(); emit_int32( op(arith_op) | fcn(0) | op3(saved_op3)); } +inline void Assembler::restored() { v9_only(); emit_int32( op(arith_op) | fcn(1) | op3(saved_op3)); } + inline void Assembler::sethi( int imm22a, Register d, RelocationHolder const& rspec ) { emit_data( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(imm22a), rspec); } +inline void Assembler::sll( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | rs2(s2) ); } +inline void Assembler::sll( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); } +inline void Assembler::srl( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | rs2(s2) ); } +inline void Assembler::srl( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); } +inline void Assembler::sra( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | rs2(s2) ); } +inline void Assembler::sra( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); } + +inline void Assembler::sllx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | rs2(s2) ); } +inline void Assembler::sllx( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); } +inline void Assembler::srlx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | rs2(s2) ); } +inline void Assembler::srlx( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); } +inline void Assembler::srax( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | rs2(s2) ); } +inline void Assembler::srax( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); } + +inline void Assembler::sir( int simm13a ) { emit_int32( op(arith_op) | fcn(15) | op3(sir_op3) | immed(true) | simm(simm13a, 13)); } + + // pp 221 + +inline void Assembler::stbar() { emit_int32( op(arith_op) | op3(membar_op3) | u_field(15, 18, 14)); } + // pp 222 inline void Assembler::stf( FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2) { emit_int32( op(ldst_op) | fd(d, w) | alt_op3(stf_op3, w) | rs1(s1) | rs2(s2) ); } @@ -122,6 +328,9 @@ inline void Assembler::stf( FloatRegisterImpl::Width w, FloatRegister d, Regi inline void Assembler::stxfsr( Register s1, Register s2) { v9_only(); emit_int32( op(ldst_op) | rd(G1) | op3(stfsr_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::stxfsr( Register s1, int simm13a) { v9_only(); emit_data( op(ldst_op) | rd(G1) | op3(stfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2, int ia ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + // p 226 inline void Assembler::stb( Register d, Register s1, Register s2) { emit_int32( op(ldst_op) | rd(d) | op3(stb_op3) | rs1(s1) | rs2(s2) ); } @@ -137,9 +346,103 @@ inline void Assembler::stx( Register d, Register s1, int simm13a) { v9_only(); inline void Assembler::std( Register d, Register s1, Register s2) { v9_dep(); assert(d->is_even(), "not even"); emit_int32( op(ldst_op) | rd(d) | op3(std_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::std( Register d, Register s1, int simm13a) { v9_dep(); assert(d->is_even(), "not even"); emit_data( op(ldst_op) | rd(d) | op3(std_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::stba( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::stba( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::stha( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::stha( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::stwa( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::stwa( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::stxa( Register d, Register s1, Register s2, int ia ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::stxa( Register d, Register s1, int simm13a ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::stda( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::stda( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +// pp 230 + +inline void Assembler::sub( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::sub( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +inline void Assembler::subcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::subcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::subc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::subc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } +inline void Assembler::subccc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); } +inline void Assembler::subccc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + // pp 231 inline void Assembler::swap( Register s1, Register s2, Register d) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::swap( Register s1, int simm13a, Register d) { v9_dep(); emit_data( op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::swapa( Register s1, Register s2, int ia, Register d ) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); } +inline void Assembler::swapa( Register s1, int simm13a, Register d ) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +// pp 234, note op in book is wrong, see pp 268 + +inline void Assembler::taddcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(taddcc_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::taddcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(taddcc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +// pp 235 + +inline void Assembler::tsubcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(tsubcc_op3 ) | rs1(s1) | rs2(s2) ); } +inline void Assembler::tsubcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(tsubcc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); } + +// pp 237 + +inline void Assembler::trap( Condition c, CC cc, Register s1, Register s2 ) { emit_int32( op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | rs2(s2)); } +inline void Assembler::trap( Condition c, CC cc, Register s1, int trapa ) { emit_int32( op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | immed(true) | u_field(trapa, 6, 0)); } +// simple uncond. trap +inline void Assembler::trap( int trapa ) { trap( always, icc, G0, trapa ); } + +inline void Assembler::wry(Register d) { v9_dep(); emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(0, 29, 25)); } +inline void Assembler::wrccr(Register s) { v9_only(); emit_int32(op(arith_op) | rs1(s) | op3(wrreg_op3) | u_field(2, 29, 25)); } +inline void Assembler::wrccr(Register s, int simm13a) { v9_only(); emit_int32(op(arith_op) | rs1(s) | op3(wrreg_op3) | u_field(2, 29, 25) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::wrasi(Register d) { v9_only(); emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25)); } +// wrasi(d, imm) stores (d xor imm) to asi +inline void Assembler::wrasi(Register d, int simm13a) { v9_only(); emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25) | immed(true) | simm(simm13a, 13)); } +inline void Assembler::wrfprs(Register d) { v9_only(); emit_int32(op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(6, 29, 25)); } + +inline void Assembler::alignaddr( Register s1, Register s2, Register d ) { vis1_only(); emit_int32( op(arith_op) | rd(d) | op3(alignaddr_op3) | rs1(s1) | opf(alignaddr_opf) | rs2(s2)); } + +inline void Assembler::faligndata( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(faligndata_op3) | fs1(s1, FloatRegisterImpl::D) | opf(faligndata_opf) | fs2(s2, FloatRegisterImpl::D)); } + +inline void Assembler::fzero( FloatRegisterImpl::Width w, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fzero_op3) | opf(0x62 - w)); } + +inline void Assembler::fsrc2( FloatRegisterImpl::Width w, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fsrc_op3) | opf(0x7A - w) | fs2(s2, w)); } + +inline void Assembler::fnot1( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fnot_op3) | fs1(s1, w) | opf(0x6C - w)); } + +inline void Assembler::fpmerge( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis1_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(0x36) | fs1(s1, FloatRegisterImpl::S) | opf(0x4b) | fs2(s2, FloatRegisterImpl::S)); } + +inline void Assembler::stpartialf( Register s1, Register s2, FloatRegister d, int ia ) { vis1_only(); emit_int32( op(ldst_op) | fd(d, FloatRegisterImpl::D) | op3(stpartialf_op3) | rs1(s1) | imm_asi(ia) | rs2(s2)); } + +// VIS2 instructions + +inline void Assembler::edge8n( Register s1, Register s2, Register d ) { vis2_only(); emit_int32( op(arith_op) | rd(d) | op3(edge_op3) | rs1(s1) | opf(edge8n_opf) | rs2(s2)); } + +inline void Assembler::bmask( Register s1, Register s2, Register d ) { vis2_only(); emit_int32( op(arith_op) | rd(d) | op3(bmask_op3) | rs1(s1) | opf(bmask_opf) | rs2(s2)); } +inline void Assembler::bshuffle( FloatRegister s1, FloatRegister s2, FloatRegister d ) { vis2_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(bshuffle_op3) | fs1(s1, FloatRegisterImpl::D) | opf(bshuffle_opf) | fs2(s2, FloatRegisterImpl::D)); } + +// VIS3 instructions + +inline void Assembler::movstosw( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstosw_opf) | fs2(s, FloatRegisterImpl::S)); } +inline void Assembler::movstouw( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstouw_opf) | fs2(s, FloatRegisterImpl::S)); } +inline void Assembler::movdtox( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mdtox_opf) | fs2(s, FloatRegisterImpl::D)); } + +inline void Assembler::movwtos( Register s, FloatRegister d ) { vis3_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(mftoi_op3) | opf(mwtos_opf) | rs2(s)); } +inline void Assembler::movxtod( Register s, FloatRegister d ) { vis3_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(mftoi_op3) | opf(mxtod_opf) | rs2(s)); } + +inline void Assembler::xmulx(Register s1, Register s2, Register d) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulx_opf) | rs2(s2)); } +inline void Assembler::xmulxhi(Register s1, Register s2, Register d) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(xmulx_op3) | rs1(s1) | opf(xmulxhi_opf) | rs2(s2)); } + +// Crypto SHA instructions + +inline void Assembler::sha1() { sha1_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha1_opf)); } +inline void Assembler::sha256() { sha256_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha256_opf)); } +inline void Assembler::sha512() { sha512_only(); emit_int32( op(arith_op) | op3(sha_op3) | opf(sha512_opf)); } + +// CRC32C instruction + +inline void Assembler::crc32c( FloatRegister s1, FloatRegister s2, FloatRegister d ) { crc32c_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(crc32c_op3) | fs1(s1, FloatRegisterImpl::D) | opf(crc32c_opf) | fs2(s2, FloatRegisterImpl::D)); } + #endif // CPU_SPARC_VM_ASSEMBLER_SPARC_INLINE_HPP diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp index 0c4fc97cc6b..baee6280a47 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp @@ -181,19 +181,6 @@ void MacroAssembler::null_check(Register reg, int offset) { // Ring buffer jumps -#ifndef PRODUCT -void MacroAssembler::ret( bool trace ) { if (trace) { - mov(I7, O7); // traceable register - JMP(O7, 2 * BytesPerInstWord); - } else { - jmpl( I7, 2 * BytesPerInstWord, G0 ); - } - } - -void MacroAssembler::retl( bool trace ) { if (trace) JMP(O7, 2 * BytesPerInstWord); - else jmpl( O7, 2 * BytesPerInstWord, G0 ); } -#endif /* PRODUCT */ - void MacroAssembler::jmp2(Register r1, Register r2, const char* file, int line ) { assert_not_delayed(); diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp index b9e34133328..3443c3f3a87 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp @@ -720,8 +720,8 @@ class MacroAssembler : public Assembler { inline int get_pc( Register d ); // Sparc shorthands(pp 85, V8 manual, pp 289 V9 manual) - inline void cmp( Register s1, Register s2 ) { subcc( s1, s2, G0 ); } - inline void cmp( Register s1, int simm13a ) { subcc( s1, simm13a, G0 ); } + inline void cmp( Register s1, Register s2 ); + inline void cmp( Register s1, int simm13a ); inline void jmp( Register s1, Register s2 ); inline void jmp( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() ); @@ -741,23 +741,10 @@ class MacroAssembler : public Assembler { inline void iprefetch( address d, relocInfo::relocType rt = relocInfo::none ); inline void iprefetch( Label& L); - inline void tst( Register s ) { orcc( G0, s, G0 ); } + inline void tst( Register s ); -#ifdef PRODUCT - inline void ret( bool trace = TraceJumps ) { if (trace) { - mov(I7, O7); // traceable register - JMP(O7, 2 * BytesPerInstWord); - } else { - jmpl( I7, 2 * BytesPerInstWord, G0 ); - } - } - - inline void retl( bool trace = TraceJumps ) { if (trace) JMP(O7, 2 * BytesPerInstWord); - else jmpl( O7, 2 * BytesPerInstWord, G0 ); } -#else - void ret( bool trace = TraceJumps ); - void retl( bool trace = TraceJumps ); -#endif /* PRODUCT */ + inline void ret( bool trace = TraceJumps ); + inline void retl( bool trace = TraceJumps ); // Required platform-specific helpers for Label::patch_instructions. // They _shadow_ the declarations in AbstractAssembler, which are undefined. @@ -790,26 +777,20 @@ public: static int insts_for_set64(jlong value); // sign-extend 32 to 64 - inline void signx( Register s, Register d ) { sra( s, G0, d); } - inline void signx( Register d ) { sra( d, G0, d); } + inline void signx( Register s, Register d ); + inline void signx( Register d ); - inline void not1( Register s, Register d ) { xnor( s, G0, d ); } - inline void not1( Register d ) { xnor( d, G0, d ); } + inline void not1( Register s, Register d ); + inline void not1( Register d ); - inline void neg( Register s, Register d ) { sub( G0, s, d ); } - inline void neg( Register d ) { sub( G0, d, d ); } + inline void neg( Register s, Register d ); + inline void neg( Register d ); - inline void cas( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY); } - inline void casx( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY); } + inline void cas( Register s1, Register s2, Register d); + inline void casx( Register s1, Register s2, Register d); // Functions for isolating 64 bit atomic swaps for LP64 // cas_ptr will perform cas for 32 bit VM's and casx for 64 bit VM's - inline void cas_ptr( Register s1, Register s2, Register d) { -#ifdef _LP64 - casx( s1, s2, d ); -#else - cas( s1, s2, d ); -#endif - } + inline void cas_ptr( Register s1, Register s2, Register d); // Functions for isolating 64 bit shifts for LP64 inline void sll_ptr( Register s1, Register s2, Register d ); @@ -819,14 +800,14 @@ public: inline void srl_ptr( Register s1, int imm6a, Register d ); // little-endian - inline void casl( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY_LITTLE); } - inline void casxl( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY_LITTLE); } + inline void casl( Register s1, Register s2, Register d); + inline void casxl( Register s1, Register s2, Register d); - inline void inc( Register d, int const13 = 1 ) { add( d, const13, d); } - inline void inccc( Register d, int const13 = 1 ) { addcc( d, const13, d); } + inline void inc( Register d, int const13 = 1 ); + inline void inccc( Register d, int const13 = 1 ); - inline void dec( Register d, int const13 = 1 ) { sub( d, const13, d); } - inline void deccc( Register d, int const13 = 1 ) { subcc( d, const13, d); } + inline void dec( Register d, int const13 = 1 ); + inline void deccc( Register d, int const13 = 1 ); using Assembler::add; inline void add(Register s1, int simm13a, Register d, relocInfo::relocType rtype); @@ -837,19 +818,19 @@ public: using Assembler::andn; inline void andn( Register s1, RegisterOrConstant s2, Register d); - inline void btst( Register s1, Register s2 ) { andcc( s1, s2, G0 ); } - inline void btst( int simm13a, Register s ) { andcc( s, simm13a, G0 ); } + inline void btst( Register s1, Register s2 ); + inline void btst( int simm13a, Register s ); - inline void bset( Register s1, Register s2 ) { or3( s1, s2, s2 ); } - inline void bset( int simm13a, Register s ) { or3( s, simm13a, s ); } + inline void bset( Register s1, Register s2 ); + inline void bset( int simm13a, Register s ); - inline void bclr( Register s1, Register s2 ) { andn( s1, s2, s2 ); } - inline void bclr( int simm13a, Register s ) { andn( s, simm13a, s ); } + inline void bclr( Register s1, Register s2 ); + inline void bclr( int simm13a, Register s ); - inline void btog( Register s1, Register s2 ) { xor3( s1, s2, s2 ); } - inline void btog( int simm13a, Register s ) { xor3( s, simm13a, s ); } + inline void btog( Register s1, Register s2 ); + inline void btog( int simm13a, Register s ); - inline void clr( Register d ) { or3( G0, G0, d ); } + inline void clr( Register d ); inline void clrb( Register s1, Register s2); inline void clrh( Register s1, Register s2); @@ -862,9 +843,9 @@ public: inline void clrx( Register s1, int simm13a); // copy & clear upper word - inline void clruw( Register s, Register d ) { srl( s, G0, d); } + inline void clruw( Register s, Register d ); // clear upper word - inline void clruwu( Register d ) { srl( d, G0, d); } + inline void clruwu( Register d ); using Assembler::ldsb; using Assembler::ldsh; @@ -908,10 +889,10 @@ public: inline void ldf(FloatRegisterImpl::Width w, const Address& a, FloatRegister d, int offset = 0); // little-endian - inline void lduwl(Register s1, Register s2, Register d) { lduwa(s1, s2, ASI_PRIMARY_LITTLE, d); } - inline void ldswl(Register s1, Register s2, Register d) { ldswa(s1, s2, ASI_PRIMARY_LITTLE, d);} - inline void ldxl( Register s1, Register s2, Register d) { ldxa(s1, s2, ASI_PRIMARY_LITTLE, d); } - inline void ldfl(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d) { ldfa(w, s1, s2, ASI_PRIMARY_LITTLE, d); } + inline void lduwl(Register s1, Register s2, Register d); + inline void ldswl(Register s1, Register s2, Register d); + inline void ldxl( Register s1, Register s2, Register d); + inline void ldfl(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d); // membar psuedo instruction. takes into account target memory model. inline void membar( Assembler::Membar_mask_bits const7a ); @@ -920,17 +901,11 @@ public: inline bool membar_has_effect( Assembler::Membar_mask_bits const7a ); // mov pseudo instructions - inline void mov( Register s, Register d) { - if ( s != d ) or3( G0, s, d); - else assert_not_delayed(); // Put something useful in the delay slot! - } + inline void mov( Register s, Register d); - inline void mov_or_nop( Register s, Register d) { - if ( s != d ) or3( G0, s, d); - else nop(); - } + inline void mov_or_nop( Register s, Register d); - inline void mov( int simm13a, Register d) { or3( G0, simm13a, d); } + inline void mov( int simm13a, Register d); using Assembler::prefetch; inline void prefetch(const Address& a, PrefetchFcn F, int offset = 0); @@ -1005,11 +980,7 @@ public: // handy macros: - inline void round_to( Register r, int modulus ) { - assert_not_delayed(); - inc( r, modulus - 1 ); - and3( r, -modulus, r ); - } + inline void round_to( Register r, int modulus ); // -------------------------------------------------- @@ -1077,9 +1048,9 @@ public: // These are idioms to flag the need for care with accessing bools but on // this platform we assume byte size - inline void stbool(Register d, const Address& a) { stb(d, a); } - inline void ldbool(const Address& a, Register d) { ldub(a, d); } - inline void movbool( bool boolconst, Register d) { mov( (int) boolconst, d); } + inline void stbool(Register d, const Address& a); + inline void ldbool(const Address& a, Register d); + inline void movbool( bool boolconst, Register d); // klass oop manipulations if compressed void load_klass(Register src_oop, Register klass); @@ -1415,12 +1386,7 @@ public: // Stack overflow checking // Note: this clobbers G3_scratch - void bang_stack_with_offset(int offset) { - // stack grows down, caller passes positive offset - assert(offset > 0, "must bang with negative offset"); - set((-offset)+STACK_BIAS, G3_scratch); - st(G0, SP, G3_scratch); - } + inline void bang_stack_with_offset(int offset); // Writes to stack successive pages until offset reached to check for // stack overflow + shadow pages. Clobbers tsp and scratch registers. diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp index 4dd8772e010..2f1c949bb7f 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp @@ -187,6 +187,33 @@ inline void MacroAssembler::st_long( Register d, const Address& a, int offset ) #endif } +inline void MacroAssembler::stbool(Register d, const Address& a) { stb(d, a); } +inline void MacroAssembler::ldbool(const Address& a, Register d) { ldub(a, d); } +inline void MacroAssembler::movbool( bool boolconst, Register d) { mov( (int) boolconst, d); } + + +inline void MacroAssembler::signx( Register s, Register d ) { sra( s, G0, d); } +inline void MacroAssembler::signx( Register d ) { sra( d, G0, d); } + +inline void MacroAssembler::not1( Register s, Register d ) { xnor( s, G0, d ); } +inline void MacroAssembler::not1( Register d ) { xnor( d, G0, d ); } + +inline void MacroAssembler::neg( Register s, Register d ) { sub( G0, s, d ); } +inline void MacroAssembler::neg( Register d ) { sub( G0, d, d ); } + +inline void MacroAssembler::cas( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY); } +inline void MacroAssembler::casx( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY); } + +// Functions for isolating 64 bit atomic swaps for LP64 +// cas_ptr will perform cas for 32 bit VM's and casx for 64 bit VM's +inline void MacroAssembler::cas_ptr( Register s1, Register s2, Register d) { +#ifdef _LP64 + casx( s1, s2, d ); +#else + cas( s1, s2, d ); +#endif +} + // Functions for isolating 64 bit shifts for LP64 inline void MacroAssembler::sll_ptr( Register s1, Register s2, Register d ) { @@ -226,6 +253,15 @@ inline void MacroAssembler::sll_ptr( Register s1, RegisterOrConstant s2, Registe else sll_ptr(s1, s2.as_constant(), d); } +inline void MacroAssembler::casl( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY_LITTLE); } +inline void MacroAssembler::casxl( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY_LITTLE); } + +inline void MacroAssembler::inc( Register d, int const13 ) { add( d, const13, d); } +inline void MacroAssembler::inccc( Register d, int const13 ) { addcc( d, const13, d); } + +inline void MacroAssembler::dec( Register d, int const13 ) { sub( d, const13, d); } +inline void MacroAssembler::deccc( Register d, int const13 ) { subcc( d, const13, d); } + // Use the right branch for the platform inline void MacroAssembler::br( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) { @@ -341,6 +377,24 @@ inline void MacroAssembler::iprefetch( address d, relocInfo::relocType rt ) { } inline void MacroAssembler::iprefetch( Label& L) { iprefetch( target(L) ); } +inline void MacroAssembler::tst( Register s ) { orcc( G0, s, G0 ); } + +inline void MacroAssembler::ret( bool trace ) { + if (trace) { + mov(I7, O7); // traceable register + JMP(O7, 2 * BytesPerInstWord); + } else { + jmpl( I7, 2 * BytesPerInstWord, G0 ); + } +} + +inline void MacroAssembler::retl( bool trace ) { + if (trace) { + JMP(O7, 2 * BytesPerInstWord); + } else { + jmpl( O7, 2 * BytesPerInstWord, G0 ); + } +} // clobbers o7 on V8!! // returns delta from gotten pc to addr after @@ -350,6 +404,8 @@ inline int MacroAssembler::get_pc( Register d ) { return offset() - x; } +inline void MacroAssembler::cmp( Register s1, Register s2 ) { subcc( s1, s2, G0 ); } +inline void MacroAssembler::cmp( Register s1, int simm13a ) { subcc( s1, simm13a, G0 ); } // Note: All MacroAssembler::set_foo functions are defined out-of-line. @@ -525,6 +581,12 @@ inline void MacroAssembler::store_long_argument( Register s, Argument& a ) { } #endif +inline void MacroAssembler::round_to( Register r, int modulus ) { + assert_not_delayed(); + inc( r, modulus - 1 ); + and3( r, -modulus, r ); +} + inline void MacroAssembler::add(Register s1, int simm13a, Register d, relocInfo::relocType rtype) { relocate(rtype); add(s1, simm13a, d); @@ -551,6 +613,20 @@ inline void MacroAssembler::andn(Register s1, RegisterOrConstant s2, Register d) else andn(s1, s2.as_constant(), d); } +inline void MacroAssembler::btst( Register s1, Register s2 ) { andcc( s1, s2, G0 ); } +inline void MacroAssembler::btst( int simm13a, Register s ) { andcc( s, simm13a, G0 ); } + +inline void MacroAssembler::bset( Register s1, Register s2 ) { or3( s1, s2, s2 ); } +inline void MacroAssembler::bset( int simm13a, Register s ) { or3( s, simm13a, s ); } + +inline void MacroAssembler::bclr( Register s1, Register s2 ) { andn( s1, s2, s2 ); } +inline void MacroAssembler::bclr( int simm13a, Register s ) { andn( s, simm13a, s ); } + +inline void MacroAssembler::btog( Register s1, Register s2 ) { xor3( s1, s2, s2 ); } +inline void MacroAssembler::btog( int simm13a, Register s ) { xor3( s, simm13a, s ); } + +inline void MacroAssembler::clr( Register d ) { or3( G0, G0, d ); } + inline void MacroAssembler::clrb( Register s1, Register s2) { stb( G0, s1, s2 ); } inline void MacroAssembler::clrh( Register s1, Register s2) { sth( G0, s1, s2 ); } inline void MacroAssembler::clr( Register s1, Register s2) { stw( G0, s1, s2 ); } @@ -561,6 +637,9 @@ inline void MacroAssembler::clrh( Register s1, int simm13a) { sth( G0, s1, simm1 inline void MacroAssembler::clr( Register s1, int simm13a) { stw( G0, s1, simm13a); } inline void MacroAssembler::clrx( Register s1, int simm13a) { stx( G0, s1, simm13a); } +inline void MacroAssembler::clruw( Register s, Register d ) { srl( s, G0, d); } +inline void MacroAssembler::clruwu( Register d ) { srl( d, G0, d); } + #ifdef _LP64 // Make all 32 bit loads signed so 64 bit registers maintain proper sign inline void MacroAssembler::ld( Register s1, Register s2, Register d) { ldsw( s1, s2, d); } @@ -642,6 +721,11 @@ inline void MacroAssembler::ldf(FloatRegisterImpl::Width w, const Address& a, Fl } } +inline void MacroAssembler::lduwl(Register s1, Register s2, Register d) { lduwa(s1, s2, ASI_PRIMARY_LITTLE, d); } +inline void MacroAssembler::ldswl(Register s1, Register s2, Register d) { ldswa(s1, s2, ASI_PRIMARY_LITTLE, d);} +inline void MacroAssembler::ldxl( Register s1, Register s2, Register d) { ldxa(s1, s2, ASI_PRIMARY_LITTLE, d); } +inline void MacroAssembler::ldfl(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d) { ldfa(w, s1, s2, ASI_PRIMARY_LITTLE, d); } + // returns if membar generates anything, obviously this code should mirror // membar below. inline bool MacroAssembler::membar_has_effect( Membar_mask_bits const7a ) { @@ -668,6 +752,24 @@ inline void MacroAssembler::membar( Membar_mask_bits const7a ) { } } +inline void MacroAssembler::mov(Register s, Register d) { + if (s != d) { + or3(G0, s, d); + } else { + assert_not_delayed(); // Put something useful in the delay slot! + } +} + +inline void MacroAssembler::mov_or_nop(Register s, Register d) { + if (s != d) { + or3(G0, s, d); + } else { + nop(); + } +} + +inline void MacroAssembler::mov( int simm13a, Register d) { or3( G0, simm13a, d); } + inline void MacroAssembler::prefetch(const Address& a, PrefetchFcn f, int offset) { relocate(a.rspec(offset)); assert(!a.has_index(), ""); @@ -738,4 +840,11 @@ inline void MacroAssembler::swap(const Address& a, Register d, int offset) { else { swap(a.base(), a.disp() + offset, d); } } +inline void MacroAssembler::bang_stack_with_offset(int offset) { + // stack grows down, caller passes positive offset + assert(offset > 0, "must bang with negative offset"); + set((-offset)+STACK_BIAS, G3_scratch); + st(G0, SP, G3_scratch); +} + #endif // CPU_SPARC_VM_MACROASSEMBLER_SPARC_INLINE_HPP From 449bf68d35017f83481edd12ace5b349ccbf8aae Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Fri, 4 Dec 2015 15:18:46 -1000 Subject: [PATCH 028/215] 8143571: [JVMCI] Double unregistering of nmethod during unloading Reviewed-by: iveresov, twisti --- hotspot/src/share/vm/code/nmethod.cpp | 107 ++++++++++++++---- hotspot/src/share/vm/code/nmethod.hpp | 14 ++- .../src/share/vm/jvmci/jvmciCompilerToVM.cpp | 48 +++----- .../src/share/vm/jvmci/jvmciCompilerToVM.hpp | 2 - 4 files changed, 114 insertions(+), 57 deletions(-) diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index d8af2c0624b..18625bcbbe3 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -1348,6 +1348,9 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) { _state = unloaded; + // Log the unloading. + log_state_change(); + #if INCLUDE_JVMCI // The method can only be unloaded after the pointer to the installed code // Java wrapper is no longer alive. Here we need to clear out this weak @@ -1355,11 +1358,12 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) { // after the method is unregistered since the original value may be still // tracked by the rset. maybe_invalidate_installed_code(); + // Clear these out after the nmethod has been unregistered and any + // updates to the InstalledCode instance have been performed. + _jvmci_installed_code = NULL; + _speculation_log = NULL; #endif - // Log the unloading. - log_state_change(); - // The Method* is gone at this point assert(_method == NULL, "Tautology"); @@ -1470,6 +1474,9 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { // Log the transition once log_state_change(); + // Invalidate while holding the patching lock + JVMCI_ONLY(maybe_invalidate_installed_code()); + // Remove nmethod from method. // We need to check if both the _code and _from_compiled_code_entry_point // refer to this nmethod because there is a race in setting these two fields @@ -1496,6 +1503,10 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); if (nmethod_needs_unregister) { Universe::heap()->unregister_nmethod(this); +#ifdef JVMCI + _jvmci_installed_code = NULL; + _speculation_log = NULL; +#endif } flush_dependencies(NULL); } @@ -1519,8 +1530,6 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { assert(state == not_entrant, "other cases may need to be handled differently"); } - JVMCI_ONLY(maybe_invalidate_installed_code()); - if (TraceCreateZombies) { ResourceMark m; tty->print_cr("nmethod <" INTPTR_FORMAT "> %s code made %s", p2i(this), this->method() ? this->method()->name_and_sig_as_C_string() : "null", (state == not_entrant) ? "not entrant" : "zombie"); @@ -3403,26 +3412,80 @@ void nmethod::print_statistics() { #if INCLUDE_JVMCI void nmethod::clear_jvmci_installed_code() { - // This must be done carefully to maintain nmethod remembered sets properly - BarrierSet* bs = Universe::heap()->barrier_set(); - bs->write_ref_nmethod_pre(&_jvmci_installed_code, this); - _jvmci_installed_code = NULL; - bs->write_ref_nmethod_post(&_jvmci_installed_code, this); + // write_ref_method_pre/post can only be safely called at a + // safepoint or while holding the CodeCache_lock + assert(CodeCache_lock->is_locked() || + SafepointSynchronize::is_at_safepoint(), "should be performed under a lock for consistency"); + if (_jvmci_installed_code != NULL) { + // This must be done carefully to maintain nmethod remembered sets properly + BarrierSet* bs = Universe::heap()->barrier_set(); + bs->write_ref_nmethod_pre(&_jvmci_installed_code, this); + _jvmci_installed_code = NULL; + bs->write_ref_nmethod_post(&_jvmci_installed_code, this); + } } void nmethod::maybe_invalidate_installed_code() { - if (_jvmci_installed_code != NULL) { - if (!is_alive()) { - // Break the link between nmethod and InstalledCode such that the nmethod - // can subsequently be flushed safely. The link must be maintained while - // the method could have live activations since invalidateInstalledCode - // might want to invalidate all existing activations. - InstalledCode::set_address(_jvmci_installed_code, 0); - InstalledCode::set_entryPoint(_jvmci_installed_code, 0); - clear_jvmci_installed_code(); - } else if (is_not_entrant()) { - InstalledCode::set_entryPoint(_jvmci_installed_code, 0); - } + assert(Patching_lock->is_locked() || + SafepointSynchronize::is_at_safepoint(), "should be performed under a lock for consistency"); + oop installed_code = jvmci_installed_code(); + if (installed_code != NULL) { + nmethod* nm = (nmethod*)InstalledCode::address(installed_code); + if (nm == NULL || nm != this) { + // The link has been broken or the InstalledCode instance is + // associated with another nmethod so do nothing. + return; + } + if (!is_alive()) { + // Break the link between nmethod and InstalledCode such that the nmethod + // can subsequently be flushed safely. The link must be maintained while + // the method could have live activations since invalidateInstalledCode + // might want to invalidate all existing activations. + InstalledCode::set_address(installed_code, 0); + InstalledCode::set_entryPoint(installed_code, 0); + } else if (is_not_entrant()) { + // Remove the entry point so any invocation will fail but keep + // the address link around that so that existing activations can + // be invalidated. + InstalledCode::set_entryPoint(installed_code, 0); + } + } +} + +void nmethod::invalidate_installed_code(Handle installedCode, TRAPS) { + if (installedCode() == NULL) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + jlong nativeMethod = InstalledCode::address(installedCode); + nmethod* nm = (nmethod*)nativeMethod; + if (nm == NULL) { + // Nothing to do + return; + } + + nmethodLocker nml(nm); +#ifdef ASSERT + { + MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag); + // This relationship can only be checked safely under a lock + assert(nm == NULL || !nm->is_alive() || nm->jvmci_installed_code() == installedCode(), "sanity check"); + } +#endif + + if (nm->is_alive()) { + // The nmethod state machinery maintains the link between the + // HotSpotInstalledCode and nmethod* so as long as the nmethod appears to be + // alive assume there is work to do and deoptimize the nmethod. + nm->mark_for_deoptimization(); + VM_Deoptimize op; + VMThread::execute(&op); + } + + MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag); + // Check that it's still associated with the same nmethod and break + // the link if it is. + if (InstalledCode::address(installedCode) == nativeMethod) { + InstalledCode::set_address(installedCode, 0); } } diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 3f72547d518..5f9b1aa320f 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -607,10 +607,20 @@ public: #if INCLUDE_JVMCI oop jvmci_installed_code() { return _jvmci_installed_code ; } char* jvmci_installed_code_name(char* buf, size_t buflen); - void clear_jvmci_installed_code(); + + // Update the state of any InstalledCode instance associated with + // this nmethod based on the current value of _state. void maybe_invalidate_installed_code(); + + // Helper function to invalidate InstalledCode instances + static void invalidate_installed_code(Handle installed_code, TRAPS); + oop speculation_log() { return _speculation_log ; } - void set_speculation_log(oop speculation_log) { _speculation_log = speculation_log; } + + private: + void clear_jvmci_installed_code(); + + public: #endif // GC support diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index 558331e64a7..694513cc4a7 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -84,24 +84,6 @@ oop CompilerToVM::get_jvmci_type(KlassHandle klass, TRAPS) { return NULL; } -void CompilerToVM::invalidate_installed_code(Handle installedCode, TRAPS) { - if (installedCode() == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - jlong nativeMethod = InstalledCode::address(installedCode); - nmethod* nm = (nmethod*)nativeMethod; - assert(nm == NULL || nm->jvmci_installed_code() == installedCode(), "sanity check"); - if (nm != NULL && nm->is_alive()) { - // The nmethod state machinery maintains the link between the - // HotSpotInstalledCode and nmethod* so as long as the nmethod appears to be - // alive assume there is work to do and deoptimize the nmethod. - nm->mark_for_deoptimization(); - VM_Deoptimize op; - VMThread::execute(&op); - } - InstalledCode::set_address(installedCode, 0); -} - extern "C" { extern VMStructEntry* gHotSpotVMStructs; extern uint64_t gHotSpotVMStructEntryTypeNameOffset; @@ -688,18 +670,22 @@ C2V_VMENTRY(jint, installCode, (JNIEnv *jniEnv, jobject, jobject target, jobject } else { if (!installed_code_handle.is_null()) { assert(installed_code_handle->is_a(InstalledCode::klass()), "wrong type"); - CompilerToVM::invalidate_installed_code(installed_code_handle, CHECK_0); - InstalledCode::set_address(installed_code_handle, (jlong) cb); - InstalledCode::set_version(installed_code_handle, InstalledCode::version(installed_code_handle) + 1); - if (cb->is_nmethod()) { - InstalledCode::set_entryPoint(installed_code_handle, (jlong) cb->as_nmethod_or_null()->verified_entry_point()); - } else { - InstalledCode::set_entryPoint(installed_code_handle, (jlong) cb->code_begin()); - } - if (installed_code_handle->is_a(HotSpotInstalledCode::klass())) { - HotSpotInstalledCode::set_size(installed_code_handle, cb->size()); - HotSpotInstalledCode::set_codeStart(installed_code_handle, (jlong) cb->code_begin()); - HotSpotInstalledCode::set_codeSize(installed_code_handle, cb->code_size()); + nmethod::invalidate_installed_code(installed_code_handle, CHECK_0); + { + // Ensure that all updates to the InstalledCode fields are consistent. + MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag); + InstalledCode::set_address(installed_code_handle, (jlong) cb); + InstalledCode::set_version(installed_code_handle, InstalledCode::version(installed_code_handle) + 1); + if (cb->is_nmethod()) { + InstalledCode::set_entryPoint(installed_code_handle, (jlong) cb->as_nmethod_or_null()->verified_entry_point()); + } else { + InstalledCode::set_entryPoint(installed_code_handle, (jlong) cb->code_begin()); + } + if (installed_code_handle->is_a(HotSpotInstalledCode::klass())) { + HotSpotInstalledCode::set_size(installed_code_handle, cb->size()); + HotSpotInstalledCode::set_codeStart(installed_code_handle, (jlong) cb->code_begin()); + HotSpotInstalledCode::set_codeSize(installed_code_handle, cb->code_size()); + } } nmethod* nm = cb->as_nmethod_or_null(); if (nm != NULL && installed_code_handle->is_scavengable()) { @@ -971,7 +957,7 @@ C2V_END C2V_VMENTRY(void, invalidateInstalledCode, (JNIEnv*, jobject, jobject installed_code)) Handle installed_code_handle = JNIHandles::resolve(installed_code); - CompilerToVM::invalidate_installed_code(installed_code_handle, CHECK); + nmethod::invalidate_installed_code(installed_code_handle, CHECK); C2V_END C2V_VMENTRY(jobject, readUncompressedOop, (JNIEnv*, jobject, jlong addr)) diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp index 4acce0bcb93..35f17689f1e 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp @@ -97,8 +97,6 @@ public: static oop get_jvmci_method(const methodHandle& method, TRAPS); static oop get_jvmci_type(KlassHandle klass, TRAPS); - - static void invalidate_installed_code(Handle installedCode, TRAPS); }; class JavaArgumentUnboxer : public SignatureIterator { From cdb4a75a00102ecf64d363b495b28499f7c3588c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Bourg=C3=A8s?= Date: Sat, 5 Dec 2015 09:48:43 -0800 Subject: [PATCH 029/215] 8144630: Use PrivilegedAction to create Thread in Marlin RendererStats Reviewed-by: prr, flar --- .../sun/java2d/marlin/RendererStats.java | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java index 6ddb5253372..4588bf270b3 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererStats.java @@ -25,6 +25,8 @@ package sun.java2d.marlin; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentLinkedQueue; @@ -32,6 +34,7 @@ import static sun.java2d.marlin.MarlinUtils.logInfo; import sun.java2d.marlin.stats.Histogram; import sun.java2d.marlin.stats.Monitor; import sun.java2d.marlin.stats.StatLong; +import sun.awt.util.ThreadGroupUtils; /** * This class gathers global rendering statistics for debugging purposes only @@ -237,22 +240,33 @@ public final class RendererStats implements MarlinConst { private RendererStats() { super(); - Runtime.getRuntime().addShutdownHook(new Thread() { - @Override - public void run() { - dump(); - } - }); + AccessController.doPrivileged( + (PrivilegedAction) () -> { + final Thread hook = new Thread( + ThreadGroupUtils.getRootThreadGroup(), + new Runnable() { + @Override + public void run() { + dump(); + } + }, + "MarlinStatsHook" + ); + hook.setContextClassLoader(null); + Runtime.getRuntime().addShutdownHook(hook); - if (useDumpThread) { - final Timer statTimer = new Timer("RendererStats"); - statTimer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - dump(); + if (useDumpThread) { + final Timer statTimer = new Timer("RendererStats"); + statTimer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + dump(); + } + }, statDump, statDump); } - }, statDump, statDump); - } + return null; + } + ); } void dump() { From e12241b6136000a4804f81e32a92b1dc5c863bc8 Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Mon, 7 Dec 2015 12:31:25 +0100 Subject: [PATCH 030/215] 8144308: com/sun/jdi/SuspendThreadTest.java failed with "transport error 202: send failed: Broken pipe" Reviewed-by: sla --- jdk/test/com/sun/jdi/SuspendThreadTest.java | 119 +++++++++++--------- 1 file changed, 63 insertions(+), 56 deletions(-) diff --git a/jdk/test/com/sun/jdi/SuspendThreadTest.java b/jdk/test/com/sun/jdi/SuspendThreadTest.java index c70a58bff37..49b488864d5 100644 --- a/jdk/test/com/sun/jdi/SuspendThreadTest.java +++ b/jdk/test/com/sun/jdi/SuspendThreadTest.java @@ -42,6 +42,7 @@ import com.sun.jdi.request.*; class SuspendThreadTarg { public static long count; + public static boolean active = true; public static void bkpt() { count++; @@ -53,7 +54,7 @@ class SuspendThreadTarg { // We need this to be running so the bkpt // can be hit immediately when it is enabled // in the back-end. - while(count >= 0) { + while(active) { bkpt(); } System.out.println("Goodbye from SuspendThreadTarg, count = " + count); @@ -82,9 +83,9 @@ public class SuspendThreadTest extends TestScaffold { // to guard against spurious wakeups from bkptSignal.wait() boolean signalSent; // signal that a breakpoint has happened - Object bkptSignal = new Object() {}; + final private Object bkptSignal = new Object() {}; BreakpointRequest bkptRequest; - Field debuggeeCountField; + Field debuggeeCountField, debuggeeActiveField; // When we get a bkpt we want to disable the request, // resume the debuggee, and then re-enable the request @@ -119,65 +120,71 @@ public class SuspendThreadTest extends TestScaffold { /********** test core **********/ protected void runTests() throws Exception { - /* - * Get to the top of main() - * to determine targetClass and mainThread - */ - BreakpointEvent bpe = startToMain("SuspendThreadTarg"); - targetClass = (ClassType)bpe.location().declaringType(); - mainThread = bpe.thread(); - EventRequestManager erm = vm().eventRequestManager(); - - Location loc1 = findMethod(targetClass, "bkpt", "()V").location(); - - bkptRequest = erm.createBreakpointRequest(loc1); - - // Without this, it is a SUSPEND_ALL bkpt and the test will pass - bkptRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); - bkptRequest.enable(); - - debuggeeCountField = targetClass.fieldByName("count"); try { - addListener (this); - } catch (Exception ex){ - ex.printStackTrace(); - failure("failure: Could not add listener"); - throw new Exception("SuspendThreadTest: failed", ex); - } + /* + * Get to the top of main() + * to determine targetClass and mainThread + */ + BreakpointEvent bpe = startToMain("SuspendThreadTarg"); + targetClass = (ClassType)bpe.location().declaringType(); + mainThread = bpe.thread(); + EventRequestManager erm = vm().eventRequestManager(); - int prevBkptCount; - vm().resume(); - synchronized (bkptSignal) { - while (bkptCount < maxBkpts) { - prevBkptCount = bkptCount; - // If we don't get a bkpt within 5 secs, - // the test fails - signalSent = false; - do { - try { - bkptSignal.wait(5000); - } catch (InterruptedException ee) { + Location loc1 = findMethod(targetClass, "bkpt", "()V").location(); + + bkptRequest = erm.createBreakpointRequest(loc1); + + // Without this, it is a SUSPEND_ALL bkpt and the test will pass + bkptRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); + bkptRequest.enable(); + + debuggeeCountField = targetClass.fieldByName("count"); + debuggeeActiveField = targetClass.fieldByName("active"); + try { + addListener (this); + } catch (Exception ex){ + ex.printStackTrace(); + failure("failure: Could not add listener"); + throw new Exception("SuspendThreadTest: failed", ex); + } + + int prevBkptCount; + vm().resume(); + synchronized (bkptSignal) { + while (bkptCount < maxBkpts) { + prevBkptCount = bkptCount; + // If we don't get a bkpt within 5 secs, + // the test fails + signalSent = false; + do { + try { + bkptSignal.wait(5000); + } catch (InterruptedException ee) { + } + } while (signalSent == false); + if (prevBkptCount == bkptCount) { + failure("failure: test hung"); + break; } - } while (signalSent == false); - if (prevBkptCount == bkptCount) { - failure("failure: test hung"); - break; } } - } - println("done with loop"); - bkptRequest.disable(); - removeListener(this); + println("done with loop"); + bkptRequest.disable(); + removeListener(this); - - /* - * deal with results of test - * if anything has called failure("foo") testFailed will be true - */ - if (!testFailed) { - println("SuspendThreadTest: passed"); - } else { - throw new Exception("SuspendThreadTest: failed"); + /* + * deal with results of test + * if anything has called failure("foo") testFailed will be true + */ + if (!testFailed) { + println("SuspendThreadTest: passed"); + } else { + throw new Exception("SuspendThreadTest: failed"); + } + } finally { + if (targetClass != null && debuggeeActiveField != null) { + targetClass.setValue(debuggeeActiveField, vm().mirrorOf(false)); + } } } } From b7ad80c79fde16d00a6e9a3f5d920b3ef8fd6cf3 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Mon, 7 Dec 2015 15:01:24 +0100 Subject: [PATCH 031/215] 8144822: PPC64: Fix build after 8072008 Reviewed-by: goetz --- hotspot/src/cpu/ppc/vm/ppc.ad | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index 615f74eecf9..781b4038229 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -3401,8 +3401,8 @@ encode %{ CallStubImpl::emit_trampoline_stub(_masm, entry_point_toc_offset, start_offset); if (ciEnv::current()->failing()) { return; } // Code cache may be full. int method_index = resolved_method_index(cbuf); - __ relocate(_optimized_virtual ? opt_virtual_call_Relocate::spec(method_index) - : static_call_Relocate::spec(method_index)); + __ relocate(_optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) + : static_call_Relocation::spec(method_index)); } // The real call. From 2d9a6cfd3f4ebe81428fb759be0498e7e2bff129 Mon Sep 17 00:00:00 2001 From: Vivek R Deshpande Date: Mon, 7 Dec 2015 16:35:07 -0800 Subject: [PATCH 032/215] 8143355: Update for addition of vectorizedMismatch intrinsic for x86 Co-authored-by: Liqi Yi Reviewed-by: kvn --- .../src/cpu/aarch64/vm/vm_version_aarch64.cpp | 5 + hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp | 5 + hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp | 5 + hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp | 173 +++++++++++++++++- hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp | 4 +- .../src/cpu/x86/vm/stubGenerator_x86_64.cpp | 52 +++++- hotspot/src/cpu/x86/vm/vm_version_x86.cpp | 19 ++ hotspot/src/share/vm/classfile/vmSymbols.cpp | 3 + hotspot/src/share/vm/classfile/vmSymbols.hpp | 5 + hotspot/src/share/vm/opto/c2compiler.cpp | 1 + hotspot/src/share/vm/opto/escape.cpp | 3 +- hotspot/src/share/vm/opto/library_call.cpp | 48 +++++ hotspot/src/share/vm/opto/runtime.cpp | 20 ++ hotspot/src/share/vm/opto/runtime.hpp | 2 + hotspot/src/share/vm/runtime/globals.hpp | 3 + hotspot/src/share/vm/runtime/stubRoutines.cpp | 2 + hotspot/src/share/vm/runtime/stubRoutines.hpp | 4 + hotspot/src/share/vm/runtime/vmStructs.cpp | 1 + 18 files changed, 351 insertions(+), 4 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp index 37c0e5bbb63..72cd0375f52 100644 --- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp @@ -182,6 +182,11 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseAdler32Intrinsics, true); } + if (UseVectorizedMismatchIntrinsic) { + warning("UseVectorizedMismatchIntrinsic specified, but not available on this CPU."); + FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); + } + if (auxv & HWCAP_AES) { UseAES = UseAES || FLAG_IS_DEFAULT(UseAES); UseAESIntrinsics = diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index 774d90b5cf1..5228c2749e3 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -223,6 +223,11 @@ void VM_Version::initialize() { UseMultiplyToLenIntrinsic = true; } + if (UseVectorizedMismatchIntrinsic) { + warning("UseVectorizedMismatchIntrinsic specified, but not available on this CPU."); + FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); + } + // Adjust RTM (Restricted Transactional Memory) flags. if (!has_tcheck() && UseRTMLocking) { // Can't continue because UseRTMLocking affects UseBiasedLocking flag diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index e6a79435447..a8b7964e3f7 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -356,6 +356,11 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); } + if (UseVectorizedMismatchIntrinsic) { + warning("UseVectorizedMismatchIntrinsic specified, but not available on this CPU."); + FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); + } + if (FLAG_IS_DEFAULT(ContendedPaddingWidth) && (cache_line_size > ContendedPaddingWidth)) ContendedPaddingWidth = cache_line_size; diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 69a0d562df1..2ccee91a6cd 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -9439,13 +9439,184 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi pop(tmp1); } +void MacroAssembler::vectorized_mismatch(Register obja, Register objb, Register length, Register log2_array_indxscale, + Register result, Register tmp1, Register tmp2, XMMRegister rymm0, XMMRegister rymm1, XMMRegister rymm2){ + assert(UseSSE42Intrinsics, "SSE4.2 must be enabled."); + Label VECTOR32_LOOP, VECTOR16_LOOP, VECTOR8_LOOP, VECTOR4_LOOP; + Label VECTOR16_TAIL, VECTOR8_TAIL, VECTOR4_TAIL; + Label VECTOR32_NOT_EQUAL, VECTOR16_NOT_EQUAL, VECTOR8_NOT_EQUAL, VECTOR4_NOT_EQUAL; + Label SAME_TILL_END, DONE; + Label BYTES_LOOP, BYTES_TAIL, BYTES_NOT_EQUAL; + + //scale is in rcx in both Win64 and Unix + ShortBranchVerifier sbv(this); + + shlq(length); + xorq(result, result); + + cmpq(length, 8); + jcc(Assembler::equal, VECTOR8_LOOP); + jcc(Assembler::less, VECTOR4_TAIL); + + if (UseAVX >= 2){ + + cmpq(length, 16); + jcc(Assembler::equal, VECTOR16_LOOP); + jcc(Assembler::less, VECTOR8_LOOP); + + cmpq(length, 32); + jccb(Assembler::less, VECTOR16_TAIL); + + subq(length, 32); + bind(VECTOR32_LOOP); + vmovdqu(rymm0, Address(obja, result)); + vmovdqu(rymm1, Address(objb, result)); + vpxor(rymm2, rymm0, rymm1, Assembler::AVX_256bit); + vptest(rymm2, rymm2); + jcc(Assembler::notZero, VECTOR32_NOT_EQUAL);//mismatch found + addq(result, 32); + subq(length, 32); + jccb(Assembler::greaterEqual, VECTOR32_LOOP); + addq(length, 32); + jcc(Assembler::equal, SAME_TILL_END); + //falling through if less than 32 bytes left //close the branch here. + + bind(VECTOR16_TAIL); + cmpq(length, 16); + jccb(Assembler::less, VECTOR8_TAIL); + bind(VECTOR16_LOOP); + movdqu(rymm0, Address(obja, result)); + movdqu(rymm1, Address(objb, result)); + vpxor(rymm2, rymm0, rymm1, Assembler::AVX_128bit); + ptest(rymm2, rymm2); + jcc(Assembler::notZero, VECTOR16_NOT_EQUAL);//mismatch found + addq(result, 16); + subq(length, 16); + jcc(Assembler::equal, SAME_TILL_END); + //falling through if less than 16 bytes left + } else {//regular intrinsics + + cmpq(length, 16); + jccb(Assembler::less, VECTOR8_TAIL); + + subq(length, 16); + bind(VECTOR16_LOOP); + movdqu(rymm0, Address(obja, result)); + movdqu(rymm1, Address(objb, result)); + pxor(rymm0, rymm1); + ptest(rymm0, rymm0); + jcc(Assembler::notZero, VECTOR16_NOT_EQUAL);//mismatch found + addq(result, 16); + subq(length, 16); + jccb(Assembler::greaterEqual, VECTOR16_LOOP); + addq(length, 16); + jcc(Assembler::equal, SAME_TILL_END); + //falling through if less than 16 bytes left + } + + bind(VECTOR8_TAIL); + cmpq(length, 8); + jccb(Assembler::less, VECTOR4_TAIL); + bind(VECTOR8_LOOP); + movq(tmp1, Address(obja, result)); + movq(tmp2, Address(objb, result)); + xorq(tmp1, tmp2); + testq(tmp1, tmp1); + jcc(Assembler::notZero, VECTOR8_NOT_EQUAL);//mismatch found + addq(result, 8); + subq(length, 8); + jcc(Assembler::equal, SAME_TILL_END); + //falling through if less than 8 bytes left + + bind(VECTOR4_TAIL); + cmpq(length, 4); + jccb(Assembler::less, BYTES_TAIL); + bind(VECTOR4_LOOP); + movl(tmp1, Address(obja, result)); + xorl(tmp1, Address(objb, result)); + testl(tmp1, tmp1); + jcc(Assembler::notZero, VECTOR4_NOT_EQUAL);//mismatch found + addq(result, 4); + subq(length, 4); + jcc(Assembler::equal, SAME_TILL_END); + //falling through if less than 4 bytes left + + bind(BYTES_TAIL); + bind(BYTES_LOOP); + load_unsigned_byte(tmp1, Address(obja, result)); + load_unsigned_byte(tmp2, Address(objb, result)); + xorl(tmp1, tmp2); + testl(tmp1, tmp1); + jccb(Assembler::notZero, BYTES_NOT_EQUAL);//mismatch found + decq(length); + jccb(Assembler::zero, SAME_TILL_END); + incq(result); + load_unsigned_byte(tmp1, Address(obja, result)); + load_unsigned_byte(tmp2, Address(objb, result)); + xorl(tmp1, tmp2); + testl(tmp1, tmp1); + jccb(Assembler::notZero, BYTES_NOT_EQUAL);//mismatch found + decq(length); + jccb(Assembler::zero, SAME_TILL_END); + incq(result); + load_unsigned_byte(tmp1, Address(obja, result)); + load_unsigned_byte(tmp2, Address(objb, result)); + xorl(tmp1, tmp2); + testl(tmp1, tmp1); + jccb(Assembler::notZero, BYTES_NOT_EQUAL);//mismatch found + jmpb(SAME_TILL_END); + + if (UseAVX >= 2){ + bind(VECTOR32_NOT_EQUAL); + vpcmpeqb(rymm2, rymm2, rymm2, Assembler::AVX_256bit); + vpcmpeqb(rymm0, rymm0, rymm1, Assembler::AVX_256bit); + vpxor(rymm0, rymm0, rymm2, Assembler::AVX_256bit); + vpmovmskb(tmp1, rymm0); + bsfq(tmp1, tmp1); + addq(result, tmp1); + shrq(result); + jmpb(DONE); + } + + bind(VECTOR16_NOT_EQUAL); + if (UseAVX >= 2){ + vpcmpeqb(rymm2, rymm2, rymm2, Assembler::AVX_128bit); + vpcmpeqb(rymm0, rymm0, rymm1, Assembler::AVX_128bit); + pxor(rymm0, rymm2); + } else { + pcmpeqb(rymm2, rymm2); + pxor(rymm0, rymm1); + pcmpeqb(rymm0, rymm1); + pxor(rymm0, rymm2); + } + pmovmskb(tmp1, rymm0); + bsfq(tmp1, tmp1); + addq(result, tmp1); + shrq(result); + jmpb(DONE); + + bind(VECTOR8_NOT_EQUAL); + bind(VECTOR4_NOT_EQUAL); + bsfq(tmp1, tmp1); + shrq(tmp1, 3); + addq(result, tmp1); + bind(BYTES_NOT_EQUAL); + shrq(result); + jmpb(DONE); + + bind(SAME_TILL_END); + mov64(result, -1); + + bind(DONE); +} + + //Helper functions for square_to_len() /** * Store the squares of x[], right shifted one bit (divided by 2) into z[] * Preserves x and z and modifies rest of the registers. */ - void MacroAssembler::square_rshift(Register x, Register xlen, Register z, Register tmp1, Register tmp3, Register tmp4, Register tmp5, Register rdxReg, Register raxReg) { // Perform square and right shift by 1 // Handle odd xlen case first, then for even xlen do the following diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index e29d80b12bb..719d745b3ed 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -1346,7 +1346,6 @@ public: Register carry2); void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5); - void square_rshift(Register x, Register len, Register z, Register tmp1, Register tmp3, Register tmp4, Register tmp5, Register rdxReg, Register raxReg); void multiply_add_64_bmi2(Register sum, Register op1, Register op2, Register carry, @@ -1365,6 +1364,9 @@ public: void mul_add(Register out, Register in, Register offset, Register len, Register k, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register rdxReg, Register raxReg); + void vectorized_mismatch(Register obja, Register objb, Register length, Register log2_array_indxscale, + Register result, Register tmp1, Register tmp2, + XMMRegister vec1, XMMRegister vec2, XMMRegister vec3); #endif // CRC32 code for java.util.zip.CRC32::updateBytes() intrinsic. diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index b68bedf1ad6..c704975870f 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -4054,6 +4054,54 @@ class StubGenerator: public StubCodeGenerator { return start; } + /** + * Arguments: + * + * Input: + * c_rarg0 - obja address + * c_rarg1 - objb address + * c_rarg3 - length length + * c_rarg4 - scale log2_array_indxscale + */ + address generate_vectorizedMismatch() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "vectorizedMismatch"); + address start = __ pc(); + + BLOCK_COMMENT("Entry:"); + __ enter(); + +#ifdef _WIN64 // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) + const Register scale = c_rarg0; //rcx, will exchange with r9 + const Register objb = c_rarg1; //rdx + const Register length = c_rarg2; //r8 + const Register obja = c_rarg3; //r9 + __ xchgq(obja, scale); //now obja and scale contains the correct contents + + const Register tmp1 = r10; + const Register tmp2 = r11; +#endif +#ifndef _WIN64 // Unix: rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...) + const Register obja = c_rarg0; //U:rdi + const Register objb = c_rarg1; //U:rsi + const Register length = c_rarg2; //U:rdx + const Register scale = c_rarg3; //U:rcx + const Register tmp1 = r8; + const Register tmp2 = r9; +#endif + const Register result = rax; //return value + const XMMRegister vec0 = xmm0; + const XMMRegister vec1 = xmm1; + const XMMRegister vec2 = xmm2; + + __ vectorized_mismatch(obja, objb, length, scale, result, tmp1, tmp2, vec0, vec1, vec2); + + __ leave(); + __ ret(0); + + return start; + } + /** * Arguments: * @@ -4505,7 +4553,9 @@ class StubGenerator: public StubCodeGenerator { if (UseMulAddIntrinsic) { StubRoutines::_mulAdd = generate_mulAdd(); } - + if (UseVectorizedMismatchIntrinsic) { + StubRoutines::_vectorizedMismatch = generate_vectorizedMismatch(); + } #ifndef _WINDOWS if (UseMontgomeryMultiplyIntrinsic) { StubRoutines::_montgomeryMultiply diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index eed88e81342..b458f99fac0 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -1041,6 +1041,25 @@ void VM_Version::get_processor_features() { } } +#ifdef _LP64 + if (UseSSE42Intrinsics) { + if (FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) { + UseVectorizedMismatchIntrinsic = true; + } + } else if (UseVectorizedMismatchIntrinsic) { + if (!FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) + warning("vectorizedMismatch intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); + } +#else + if (UseVectorizedMismatchIntrinsic) { + if (!FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) { + warning("vectorizedMismatch intrinsic is not available in 32-bit VM"); + } + FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); + } +#endif // _LP64 + // Use count leading zeros count instruction if available. if (supports_lzcnt()) { if (FLAG_IS_DEFAULT(UseCountLeadingZerosInstruction)) { diff --git a/hotspot/src/share/vm/classfile/vmSymbols.cpp b/hotspot/src/share/vm/classfile/vmSymbols.cpp index bfb99c67630..6f0089a77f5 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.cpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp @@ -681,6 +681,9 @@ bool vmIntrinsics::is_disabled_by_flags(const methodHandle& method) { case vmIntrinsics::_montgomerySquare: if (!UseMontgomerySquareIntrinsic) return true; break; + case vmIntrinsics::_vectorizedMismatch: + if (!UseVectorizedMismatchIntrinsic) return true; + break; case vmIntrinsics::_addExactI: case vmIntrinsics::_addExactL: case vmIntrinsics::_decrementExactI: diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index e651ad00ed9..0146b37a4ec 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -957,6 +957,11 @@ do_name( montgomerySquare_name, "implMontgomerySquare") \ do_signature(montgomerySquare_signature, "([I[IIJ[I)[I") \ \ + do_class(java_util_ArraysSupport, "java/util/ArraysSupport") \ + do_intrinsic(_vectorizedMismatch, java_util_ArraysSupport, vectorizedMismatch_name, vectorizedMismatch_signature, F_S)\ + do_name(vectorizedMismatch_name, "vectorizedMismatch") \ + do_signature(vectorizedMismatch_signature, "(Ljava/lang/Object;JLjava/lang/Object;JII)I") \ + \ /* java/lang/ref/Reference */ \ do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \ \ diff --git a/hotspot/src/share/vm/opto/c2compiler.cpp b/hotspot/src/share/vm/opto/c2compiler.cpp index c8ff9804039..689147d9f97 100644 --- a/hotspot/src/share/vm/opto/c2compiler.cpp +++ b/hotspot/src/share/vm/opto/c2compiler.cpp @@ -441,6 +441,7 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_mulAdd: case vmIntrinsics::_montgomeryMultiply: case vmIntrinsics::_montgomerySquare: + case vmIntrinsics::_vectorizedMismatch: case vmIntrinsics::_ghash_processBlocks: case vmIntrinsics::_updateCRC32: case vmIntrinsics::_updateBytesCRC32: diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index 92ed15ca3da..169cfc0113f 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -987,7 +987,8 @@ void ConnectionGraph::process_call_arguments(CallNode *call) { strcmp(call->as_CallLeaf()->_name, "squareToLen") == 0 || strcmp(call->as_CallLeaf()->_name, "mulAdd") == 0 || strcmp(call->as_CallLeaf()->_name, "montgomery_multiply") == 0 || - strcmp(call->as_CallLeaf()->_name, "montgomery_square") == 0) + strcmp(call->as_CallLeaf()->_name, "montgomery_square") == 0 || + strcmp(call->as_CallLeaf()->_name, "vectorizedMismatch") == 0) ))) { call->dump(); fatal("EA unexpected CallLeaf %s", call->as_CallLeaf()->_name); diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 694fb6f6834..6620e57be72 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -312,6 +312,7 @@ class LibraryCallKit : public GraphKit { bool inline_mulAdd(); bool inline_montgomeryMultiply(); bool inline_montgomerySquare(); + bool inline_vectorizedMismatch(); bool inline_profileBoolean(); bool inline_isCompileConstant(); @@ -720,6 +721,9 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_montgomerySquare: return inline_montgomerySquare(); + case vmIntrinsics::_vectorizedMismatch: + return inline_vectorizedMismatch(); + case vmIntrinsics::_ghash_processBlocks: return inline_ghash_processBlocks(); @@ -5581,6 +5585,50 @@ bool LibraryCallKit::inline_montgomerySquare() { return true; } +//-------------inline_vectorizedMismatch------------------------------ +bool LibraryCallKit::inline_vectorizedMismatch() { + assert(UseVectorizedMismatchIntrinsic, "not implementated on this platform"); + + address stubAddr = StubRoutines::vectorizedMismatch(); + if (stubAddr == NULL) { + return false; // Intrinsic's stub is not implemented on this platform + } + const char* stubName = "vectorizedMismatch"; + int size_l = callee()->signature()->size(); + assert(callee()->signature()->size() == 8, "vectorizedMismatch has 6 parameters"); + + Node* obja = argument(0); + Node* aoffset = argument(1); + Node* objb = argument(3); + Node* boffset = argument(4); + Node* length = argument(6); + Node* scale = argument(7); + + const Type* a_type = obja->Value(&_gvn); + const Type* b_type = objb->Value(&_gvn); + const TypeAryPtr* top_a = a_type->isa_aryptr(); + const TypeAryPtr* top_b = b_type->isa_aryptr(); + if (top_a == NULL || top_a->klass() == NULL || + top_b == NULL || top_b->klass() == NULL) { + // failed array check + return false; + } + + Node* call; + jvms()->set_should_reexecute(true); + + Node* obja_adr = make_unsafe_address(obja, aoffset); + Node* objb_adr = make_unsafe_address(objb, boffset); + + call = make_runtime_call(RC_LEAF, + OptoRuntime::vectorizedMismatch_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + obja_adr, objb_adr, length, scale); + + Node* result = _gvn.transform(new ProjNode(call, TypeFunc::Parms)); + set_result(result); + return true; +} /** * Calculate CRC32 for byte. diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp index 1ae727c105a..a42c750d465 100644 --- a/hotspot/src/share/vm/opto/runtime.cpp +++ b/hotspot/src/share/vm/opto/runtime.cpp @@ -1103,6 +1103,26 @@ const TypeFunc* OptoRuntime::montgomerySquare_Type() { return TypeFunc::make(domain, range); } +const TypeFunc* OptoRuntime::vectorizedMismatch_Type() { + // create input type (domain) + int num_args = 4; + int argcnt = num_args; + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // obja + fields[argp++] = TypePtr::NOTNULL; // objb + fields[argp++] = TypeInt::INT; // length, number of elements + fields[argp++] = TypeInt::INT; // log2scale, element size + assert(argp == TypeFunc::Parms + argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms + argcnt, fields); + + //return mismatch index (int) + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms + 0] = TypeInt::INT; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms + 1, fields); + return TypeFunc::make(domain, range); +} + // GHASH block processing const TypeFunc* OptoRuntime::ghash_processBlocks_Type() { int argcnt = 4; diff --git a/hotspot/src/share/vm/opto/runtime.hpp b/hotspot/src/share/vm/opto/runtime.hpp index 8e38f3f3a15..69e78aa8ff7 100644 --- a/hotspot/src/share/vm/opto/runtime.hpp +++ b/hotspot/src/share/vm/opto/runtime.hpp @@ -299,6 +299,8 @@ private: static const TypeFunc* mulAdd_Type(); + static const TypeFunc* vectorizedMismatch_Type(); + static const TypeFunc* ghash_processBlocks_Type(); static const TypeFunc* updateBytesCRC32_Type(); diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 9b8b1311a76..acfcd6735f4 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -855,6 +855,9 @@ public: product(bool, UseAdler32Intrinsics, false, \ "use intrinsics for java.util.zip.Adler32") \ \ + product(bool, UseVectorizedMismatchIntrinsic, false, \ + "Enables intrinsification of ArraysSupport.vectorizedMismatch()") \ + \ diagnostic(ccstrlist, DisableIntrinsic, "", \ "do not expand intrinsics whose (internal) names appear here") \ \ diff --git a/hotspot/src/share/vm/runtime/stubRoutines.cpp b/hotspot/src/share/vm/runtime/stubRoutines.cpp index fef7c0b3b03..330ca9d0a55 100644 --- a/hotspot/src/share/vm/runtime/stubRoutines.cpp +++ b/hotspot/src/share/vm/runtime/stubRoutines.cpp @@ -148,6 +148,8 @@ address StubRoutines::_mulAdd = NULL; address StubRoutines::_montgomeryMultiply = NULL; address StubRoutines::_montgomerySquare = NULL; +address StubRoutines::_vectorizedMismatch = NULL; + address StubRoutines::_dexp = NULL; address StubRoutines::_dlog = NULL; diff --git a/hotspot/src/share/vm/runtime/stubRoutines.hpp b/hotspot/src/share/vm/runtime/stubRoutines.hpp index ac198d0746c..2a9c7084786 100644 --- a/hotspot/src/share/vm/runtime/stubRoutines.hpp +++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp @@ -207,6 +207,8 @@ class StubRoutines: AllStatic { static address _montgomeryMultiply; static address _montgomerySquare; + static address _vectorizedMismatch; + static address _dexp; static address _dlog; @@ -376,6 +378,8 @@ class StubRoutines: AllStatic { static address montgomeryMultiply() { return _montgomeryMultiply; } static address montgomerySquare() { return _montgomerySquare; } + static address vectorizedMismatch() { return _vectorizedMismatch; } + static address dexp() { return _dexp; } static address dlog() { return _dlog; } diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index bda425a96df..d3e1b44de02 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -860,6 +860,7 @@ typedef CompactHashtable SymbolCompactHashTable; static_field(StubRoutines, _mulAdd, address) \ static_field(StubRoutines, _dexp, address) \ static_field(StubRoutines, _dlog, address) \ + static_field(StubRoutines, _vectorizedMismatch, address) \ static_field(StubRoutines, _jbyte_arraycopy, address) \ static_field(StubRoutines, _jshort_arraycopy, address) \ static_field(StubRoutines, _jint_arraycopy, address) \ From 682da7441854744f3be7ec3c64b3108d69ad8d49 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Tue, 8 Dec 2015 14:44:00 +0100 Subject: [PATCH 033/215] 8143817: C1: Platform dependent stack space not preserved for all runtime calls Reviewed-by: roland --- hotspot/src/share/vm/c1/c1_LIRGenerator.cpp | 23 ++++++++++++--------- hotspot/src/share/vm/c1/c1_LIRGenerator.hpp | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 98b519b58eb..8fa61f1e975 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -3055,13 +3055,16 @@ void LIRGenerator::do_IfOp(IfOp* x) { __ cmove(lir_cond(x->cond()), t_val.result(), f_val.result(), reg, as_BasicType(x->x()->type())); } -void LIRGenerator::do_RuntimeCall(address routine, int expected_arguments, Intrinsic* x) { - assert(x->number_of_arguments() == expected_arguments, "wrong type"); - LIR_Opr reg = result_register_for(x->type()); - __ call_runtime_leaf(routine, getThreadTemp(), - reg, new LIR_OprList()); - LIR_Opr result = rlock_result(x); - __ move(reg, result); +void LIRGenerator::do_RuntimeCall(address routine, Intrinsic* x) { + assert(x->number_of_arguments() == 0, "wrong type"); + // Enforce computation of _reserved_argument_area_size which is required on some platforms. + BasicTypeList signature; + CallingConvention* cc = frame_map()->c_calling_convention(&signature); + LIR_Opr reg = result_register_for(x->type()); + __ call_runtime_leaf(routine, getThreadTemp(), + reg, new LIR_OprList()); + LIR_Opr result = rlock_result(x); + __ move(reg, result); } #ifdef TRACE_HAVE_INTRINSICS @@ -3115,16 +3118,16 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) { case vmIntrinsics::_threadID: do_ThreadIDIntrinsic(x); break; case vmIntrinsics::_classID: do_ClassIDIntrinsic(x); break; case vmIntrinsics::_counterTime: - do_RuntimeCall(CAST_FROM_FN_PTR(address, TRACE_TIME_METHOD), 0, x); + do_RuntimeCall(CAST_FROM_FN_PTR(address, TRACE_TIME_METHOD), x); break; #endif case vmIntrinsics::_currentTimeMillis: - do_RuntimeCall(CAST_FROM_FN_PTR(address, os::javaTimeMillis), 0, x); + do_RuntimeCall(CAST_FROM_FN_PTR(address, os::javaTimeMillis), x); break; case vmIntrinsics::_nanoTime: - do_RuntimeCall(CAST_FROM_FN_PTR(address, os::javaTimeNanos), 0, x); + do_RuntimeCall(CAST_FROM_FN_PTR(address, os::javaTimeNanos), x); break; case vmIntrinsics::_Object_init: do_RegisterFinalizer(x); break; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp index 89f5960182a..47dd33df54e 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp @@ -439,7 +439,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { SwitchRangeArray* create_lookup_ranges(LookupSwitch* x); void do_SwitchRanges(SwitchRangeArray* x, LIR_Opr value, BlockBegin* default_sux); - void do_RuntimeCall(address routine, int expected_arguments, Intrinsic* x); + void do_RuntimeCall(address routine, Intrinsic* x); #ifdef TRACE_HAVE_INTRINSICS void do_ThreadIDIntrinsic(Intrinsic* x); void do_ClassIDIntrinsic(Intrinsic* x); From 6f27a97d77d7eab89bbb79a447168056a882c1f7 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Mon, 7 Dec 2015 15:42:47 +0100 Subject: [PATCH 034/215] 8144466: ppc64: fix argument passing through opto stubs Reviewed-by: kvn --- hotspot/make/test/JtregNative.gmk | 1 + .../aarch64/vm/globalDefinitions_aarch64.hpp | 4 ++ .../src/cpu/ppc/vm/globalDefinitions_ppc.hpp | 4 ++ .../cpu/sparc/vm/globalDefinitions_sparc.hpp | 4 ++ .../src/cpu/x86/vm/globalDefinitions_x86.hpp | 4 ++ .../cpu/zero/vm/globalDefinitions_zero.hpp | 4 ++ .../src/share/vm/opto/generateOptoStub.cpp | 59 ++++++++++------ .../TestArrayCopyOverflowArguments.java | 69 +++++++++++++++++++ .../floatingpoint/Test15FloatJNIArgs.java | 61 ++++++++++++++++ .../floatingpoint/libTest15FloatJNIArgs.c | 41 +++++++++++ 10 files changed, 229 insertions(+), 22 deletions(-) create mode 100644 hotspot/test/compiler/arraycopy/TestArrayCopyOverflowArguments.java create mode 100644 hotspot/test/compiler/floatingpoint/Test15FloatJNIArgs.java create mode 100644 hotspot/test/compiler/floatingpoint/libTest15FloatJNIArgs.c diff --git a/hotspot/make/test/JtregNative.gmk b/hotspot/make/test/JtregNative.gmk index 09c48d77aba..d49a03757e7 100644 --- a/hotspot/make/test/JtregNative.gmk +++ b/hotspot/make/test/JtregNative.gmk @@ -46,6 +46,7 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \ $(HOTSPOT_TOPDIR)/test/runtime/jni/8033445 \ $(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \ $(HOTSPOT_TOPDIR)/test/runtime/SameObject \ + $(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \ # # Add conditional directories here when needed. diff --git a/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp index d392ccf5e48..4c9d377ff09 100644 --- a/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/globalDefinitions_aarch64.hpp @@ -28,6 +28,10 @@ const int StackAlignmentInBytes = 16; +// Indicates whether the C calling conventions require that +// 32-bit integer argument values are extended to 64 bits. +const bool CCallingConventionRequiresIntsAsLongs = false; + #define SUPPORTS_NATIVE_CX8 // The maximum B/BL offset range on AArch64 is 128MB. diff --git a/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp b/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp index 542abd1bdb6..86fddbc1751 100644 --- a/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/globalDefinitions_ppc.hpp @@ -31,6 +31,10 @@ const int BytesPerInstWord = 4; const int StackAlignmentInBytes = 16; +// Indicates whether the C calling conventions require that +// 32-bit integer argument values are extended to 64 bits. +const bool CCallingConventionRequiresIntsAsLongs = true; + #define SUPPORTS_NATIVE_CX8 // The PPC CPUs are NOT multiple-copy-atomic. diff --git a/hotspot/src/cpu/sparc/vm/globalDefinitions_sparc.hpp b/hotspot/src/cpu/sparc/vm/globalDefinitions_sparc.hpp index 93432223e8d..427b7ab5f14 100644 --- a/hotspot/src/cpu/sparc/vm/globalDefinitions_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/globalDefinitions_sparc.hpp @@ -30,6 +30,10 @@ const int BytesPerInstWord = 4; const int StackAlignmentInBytes = (2*wordSize); +// Indicates whether the C calling conventions require that +// 32-bit integer argument values are extended to 64 bits. +const bool CCallingConventionRequiresIntsAsLongs = false; + #define SUPPORTS_NATIVE_CX8 // The expected size in bytes of a cache line, used to pad data structures. diff --git a/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp b/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp index 8ddbdf82ca4..b7abbacd052 100644 --- a/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp +++ b/hotspot/src/cpu/x86/vm/globalDefinitions_x86.hpp @@ -27,6 +27,10 @@ const int StackAlignmentInBytes = 16; +// Indicates whether the C calling conventions require that +// 32-bit integer argument values are extended to 64 bits. +const bool CCallingConventionRequiresIntsAsLongs = false; + #define SUPPORTS_NATIVE_CX8 // The expected size in bytes of a cache line, used to pad data structures. diff --git a/hotspot/src/cpu/zero/vm/globalDefinitions_zero.hpp b/hotspot/src/cpu/zero/vm/globalDefinitions_zero.hpp index 5956fe1cfcc..144c47e3cb9 100644 --- a/hotspot/src/cpu/zero/vm/globalDefinitions_zero.hpp +++ b/hotspot/src/cpu/zero/vm/globalDefinitions_zero.hpp @@ -28,4 +28,8 @@ #include +// Indicates whether the C calling conventions require that +// 32-bit integer argument values are extended to 64 bits. +const bool CCallingConventionRequiresIntsAsLongs = false; + #endif // CPU_ZERO_VM_GLOBALDEFINITIONS_ZERO_HPP diff --git a/hotspot/src/share/vm/opto/generateOptoStub.cpp b/hotspot/src/share/vm/opto/generateOptoStub.cpp index b3bc8999daa..48166b491fc 100644 --- a/hotspot/src/share/vm/opto/generateOptoStub.cpp +++ b/hotspot/src/share/vm/opto/generateOptoStub.cpp @@ -72,16 +72,18 @@ void GraphKit::gen_stub(address C_function, // Make up the parameters uint i; - for( i = 0; i < parm_cnt; i++ ) + for (i = 0; i < parm_cnt; i++) { map()->init_req(i, _gvn.transform(new ParmNode(start, i))); - for( ; ireq(); i++ ) + } + for ( ; ireq(); i++) { map()->init_req(i, top()); // For nicer debugging + } // GraphKit requires memory to be a MergeMemNode: set_all_memory(map()->memory()); // Get base of thread-local storage area - Node* thread = _gvn.transform( new ThreadLocalNode() ); + Node* thread = _gvn.transform(new ThreadLocalNode()); const int NoAlias = Compile::AliasIdxBot; @@ -113,21 +115,27 @@ void GraphKit::gen_stub(address C_function, //----------------------------- // Compute signature for C call. Varies from the Java signature! + const Type **fields = TypeTuple::fields(2*parm_cnt+2); uint cnt = TypeFunc::Parms; // The C routines gets the base of thread-local storage passed in as an - // extra argument. Not all calls need it, but its cheap to add here. + // extra argument. Not all calls need it, but it is cheap to add here. for (uint pcnt = cnt; pcnt < parm_cnt; pcnt++, cnt++) { - fields[cnt] = jdomain->field_at(pcnt); + const Type *f = jdomain->field_at(pcnt); + if (CCallingConventionRequiresIntsAsLongs && f->isa_int()) { + fields[cnt++] = TypeLong::LONG; + fields[cnt] = Type::HALF; // Must add an additional half for a long. + } else { + fields[cnt] = f; + } } - fields[cnt++] = TypeRawPtr::BOTTOM; // Thread-local storage // Also pass in the caller's PC, if asked for. if (return_pc) { fields[cnt++] = TypeRawPtr::BOTTOM; // Return PC } + const TypeTuple* domain = TypeTuple::make(cnt, fields); - const TypeTuple* domain = TypeTuple::make(cnt,fields); // The C routine we are about to call cannot return an oop; it can block on // exit and a GC will trash the oop while it sits in C-land. Instead, we // return the oop through TLS for runtime calls. @@ -155,37 +163,44 @@ void GraphKit::gen_stub(address C_function, rfields[TypeFunc::Parms+1] = jrange->field_at(TypeFunc::Parms+1); } } - const TypeTuple* range = TypeTuple::make(jrange->cnt(),rfields); + const TypeTuple* range = TypeTuple::make(jrange->cnt(), rfields); // Final C signature - const TypeFunc *c_sig = TypeFunc::make(domain,range); + const TypeFunc *c_sig = TypeFunc::make(domain, range); //----------------------------- - // Make the call node + // Make the call node. CallRuntimeNode *call = new CallRuntimeNode(c_sig, C_function, name, TypePtr::BOTTOM); //----------------------------- - // Fix-up the debug info for the call - call->set_jvms( new (C) JVMState(0) ); + // Fix-up the debug info for the call. + call->set_jvms(new (C) JVMState(0)); call->jvms()->set_bci(0); call->jvms()->set_offsets(cnt); - // Set fixed predefined input arguments + // Set fixed predefined input arguments. cnt = 0; - for (i = 0; i < TypeFunc::Parms; i++) - call->init_req(cnt++, map()->in(i)); - // A little too aggressive on the parm copy; return address is not an input - call->set_req(TypeFunc::ReturnAdr, top()); - for (; i < parm_cnt; i++) { // Regular input arguments + for (i = 0; i < TypeFunc::Parms; i++) { call->init_req(cnt++, map()->in(i)); } + // A little too aggressive on the parm copy; return address is not an input. + call->set_req(TypeFunc::ReturnAdr, top()); + for (; i < parm_cnt; i++) { // Regular input arguments. + const Type *f = jdomain->field_at(i); + if (CCallingConventionRequiresIntsAsLongs && f->isa_int()) { + call->init_req(cnt++, _gvn.transform(new ConvI2LNode(map()->in(i)))); + call->init_req(cnt++, top()); + } else { + call->init_req(cnt++, map()->in(i)); + } + } + call->init_req(cnt++, thread); + if (return_pc) { // Return PC, if asked for. + call->init_req(cnt++, returnadr()); + } - call->init_req( cnt++, thread ); - if( return_pc ) // Return PC, if asked for - call->init_req( cnt++, returnadr() ); _gvn.transform_no_reclaim(call); - //----------------------------- // Now set up the return results set_control( _gvn.transform( new ProjNode(call,TypeFunc::Control)) ); diff --git a/hotspot/test/compiler/arraycopy/TestArrayCopyOverflowArguments.java b/hotspot/test/compiler/arraycopy/TestArrayCopyOverflowArguments.java new file mode 100644 index 00000000000..1bfaa35e578 --- /dev/null +++ b/hotspot/test/compiler/arraycopy/TestArrayCopyOverflowArguments.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2015 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that overflowed integers passed to arraycopy don't do any harm. This might + * be the case on platforms where C-code expects that ints passed to a call + * are properly sign extended to 64 bit (e.g., PPC64, s390x). This can fail + * if slow_arraycopy_C() is commpiled by the C compiler without any imlicit + * casts (as spill stores to the stack that are done with 4-byte instruction). + * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayCopyOverflowArguments + * + */ + +public class TestArrayCopyOverflowArguments { + + // Without volatile the overflowing computation was moved up and then + // spilled to the stack. The 32-bit spill store caused proper rounding. + static volatile int mod = Integer.MAX_VALUE; + + public static int[] m1(Object src) { + if (src == null) return null; + int[] dest = new int[10]; + try { + // PPC C calling conventions require that ints are properly expanded + // to longs when passed to a function. + int pos = 8 + mod + mod; // = 0x1_0000_0006. + int start = 2 + mod + mod; // = 0x1_0000_0000. + int len = 12 + mod + mod; // = 0x1_0000_0010. + // This is supposed to call SharedRuntime::slow_arraycopy_C(). + System.arraycopy(src, pos, dest, 0, 10); + } catch (ArrayStoreException npe) { + } + return dest; + } + + static public void main(String[] args) throws Exception { + int[] src = new int[20]; + + for (int i = 0; i < 20; ++i) { + src[i] = i * (i-1); + } + + for (int i = 0; i < 20000; i++) { + m1(src); + } + } +} + diff --git a/hotspot/test/compiler/floatingpoint/Test15FloatJNIArgs.java b/hotspot/test/compiler/floatingpoint/Test15FloatJNIArgs.java new file mode 100644 index 00000000000..1425d3da016 --- /dev/null +++ b/hotspot/test/compiler/floatingpoint/Test15FloatJNIArgs.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015 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 + * 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 8139258 + * @summary Regression test for 8139258 which failed to properly pass float args + * to a jni function on ppc64le. + * @run main/othervm -Xint Test15FloatJNIArgs + * @run main/othervm -XX:+TieredCompilation -Xcomp Test15FloatJNIArgs + * @run main/othervm -XX:-TieredCompilation -Xcomp Test15FloatJNIArgs + */ + +public class Test15FloatJNIArgs { + static { + try { + System.loadLibrary("Test15FloatJNIArgs"); + } catch (UnsatisfiedLinkError e) { + System.out.println("could not load native lib: " + e); + } + } + + public static native float add15floats( + float f1, float f2, float f3, float f4, + float f5, float f6, float f7, float f8, + float f9, float f10, float f11, float f12, + float f13, float f14, float f15); + + static void test() throws Exception { + float sum = Test15FloatJNIArgs.add15floats(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); + if (sum != 15.0f) { + throw new Error("Passed 15 times 1.0f to jni function which didn't add them properly: " + sum); + } + } + + public static void main(String[] args) throws Exception { + for (int i = 0; i < 200; ++i) { + test(); + } + } +} diff --git a/hotspot/test/compiler/floatingpoint/libTest15FloatJNIArgs.c b/hotspot/test/compiler/floatingpoint/libTest15FloatJNIArgs.c new file mode 100644 index 00000000000..e31627955ca --- /dev/null +++ b/hotspot/test/compiler/floatingpoint/libTest15FloatJNIArgs.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015. All rights reserved. + * 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 + +#ifdef __cplusplus +extern "C" { +#endif + +JNIEXPORT jfloat JNICALL Java_Test15FloatJNIArgs_add15floats + (JNIEnv *env, jclass cls, + jfloat f1, jfloat f2, jfloat f3, jfloat f4, + jfloat f5, jfloat f6, jfloat f7, jfloat f8, + jfloat f9, jfloat f10, jfloat f11, jfloat f12, + jfloat f13, jfloat f14, jfloat f15) { + return f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10 + f11 + f12 + f13 + f14 + f15; +} + +#ifdef __cplusplus +} +#endif From 08a2e337c77be8952093613528751a9b905a898a Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Sun, 13 Dec 2015 22:51:13 +0100 Subject: [PATCH 035/215] 8145270: Need to eagerly initialize JVMCI compiler under -Xcomp Reviewed-by: twisti --- hotspot/src/share/vm/compiler/compileBroker.cpp | 14 +++++++++++++- hotspot/src/share/vm/compiler/compileBroker.hpp | 2 +- hotspot/src/share/vm/runtime/thread.cpp | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index e5eac46910c..9881a31435e 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -56,6 +56,7 @@ #if INCLUDE_JVMCI #include "jvmci/jvmciCompiler.hpp" #include "jvmci/jvmciRuntime.hpp" +#include "jvmci/jvmciJavaClasses.hpp" #include "runtime/vframe.hpp" #endif #ifdef COMPILER2 @@ -498,7 +499,7 @@ CompilerCounters::CompilerCounters() { // CompileBroker::compilation_init // // Initialize the Compilation object -void CompileBroker::compilation_init() { +void CompileBroker::compilation_init(TRAPS) { _last_method_compiled[0] = '\0'; // No need to initialize compilation system if we do not use it. @@ -529,6 +530,17 @@ void CompileBroker::compilation_init() { } else { c1_count = JVMCIHostThreads; } + + if (!UseInterpreter) { + // Force initialization of JVMCI compiler otherwise JVMCI + // compilations will not block until JVMCI is initialized + ResourceMark rm; + TempNewSymbol getCompiler = SymbolTable::new_symbol("getCompiler", CHECK); + TempNewSymbol sig = SymbolTable::new_symbol("()Ljdk/vm/ci/runtime/JVMCICompiler;", CHECK); + Handle jvmciRuntime = JVMCIRuntime::get_HotSpotJVMCIRuntime(CHECK); + JavaValue result(T_OBJECT); + JavaCalls::call_virtual(&result, jvmciRuntime, HotSpotJVMCIRuntime::klass(), getCompiler, sig, CHECK); + } } } #endif // INCLUDE_JVMCI diff --git a/hotspot/src/share/vm/compiler/compileBroker.hpp b/hotspot/src/share/vm/compiler/compileBroker.hpp index 9c0709aa28f..448f1f8897d 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.hpp +++ b/hotspot/src/share/vm/compiler/compileBroker.hpp @@ -276,7 +276,7 @@ public: CompileQueue *q = compile_queue(comp_level); return q != NULL ? q->size() : 0; } - static void compilation_init(); + static void compilation_init(TRAPS); static void init_compiler_thread_log(); static nmethod* compile_method(const methodHandle& method, int osr_bci, diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index db0f5d9812c..f6f00384245 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -3628,7 +3628,7 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // initialize compiler(s) #if defined(COMPILER1) || defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI - CompileBroker::compilation_init(); + CompileBroker::compilation_init(CHECK_JNI_ERR); #endif // Pre-initialize some JSR292 core classes to avoid deadlock during class loading. From e4d937a557cfc0d7395be218994751d28bcd64ff Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Mon, 14 Dec 2015 13:06:39 -0800 Subject: [PATCH 036/215] 8145338: compiler/jsr292/CallSiteDepContextTest.java fails: assert(dep_implicit_context_arg(dept) == 0) failed: sanity Reviewed-by: twisti --- hotspot/src/share/vm/code/dependencies.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/hotspot/src/share/vm/code/dependencies.cpp b/hotspot/src/share/vm/code/dependencies.cpp index c941f404276..bdb1292a4aa 100644 --- a/hotspot/src/share/vm/code/dependencies.cpp +++ b/hotspot/src/share/vm/code/dependencies.cpp @@ -346,7 +346,6 @@ void Dependencies::assert_common_2(DepType dept, } } } else { - assert(dep_implicit_context_arg(dept) == 0, "sanity"); if (note_dep_seen(dept, x0) && note_dep_seen(dept, x1)) { // look in this bucket for redundant assertions const int stride = 2; From a08d3805f07742bcf22b20bab32134b45cf01b9d Mon Sep 17 00:00:00 2001 From: Jan Civlin Date: Mon, 14 Dec 2015 14:48:30 -0800 Subject: [PATCH 037/215] 8144771: Use AVX3 instructions for string compare Co-authored-by: Michael C Berg Reviewed-by: kvn, thartmann --- hotspot/src/cpu/x86/vm/assembler_x86.cpp | 226 +++++++++++------- hotspot/src/cpu/x86/vm/assembler_x86.hpp | 16 +- hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp | 79 +++++- .../src/cpu/x86/vm/sharedRuntime_x86_64.cpp | 6 +- .../src/cpu/x86/vm/stubGenerator_x86_32.cpp | 4 +- .../src/cpu/x86/vm/stubGenerator_x86_64.cpp | 6 +- 6 files changed, 234 insertions(+), 103 deletions(-) diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.cpp b/hotspot/src/cpu/x86/vm/assembler_x86.cpp index 015a66b7900..e55fd56e78d 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp @@ -2152,33 +2152,64 @@ void Assembler::movddup(XMMRegister dst, XMMRegister src) { emit_int8(0xC0 | encode); } -void Assembler::kmovwl(KRegister dst, Register src) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); +void Assembler::kmovbl(KRegister dst, Register src) { + assert(VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(dst, knoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x92); emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::kmovbl(Register dst, KRegister src) { + assert(VM_Version::supports_avx512dq(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x93); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::kmovwl(KRegister dst, Register src) { + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x92); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::kmovwl(Register dst, KRegister src) { + assert(VM_Version::supports_evex(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x93); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::kmovdl(KRegister dst, Register src) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); - VexSimdPrefix pre = !_legacy_mode_bw ? VEX_SIMD_F2 : VEX_SIMD_NONE; + assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(dst, knoreg, src, pre, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x92); emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::kmovdl(Register dst, KRegister src) { + assert(VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x93); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::kmovql(KRegister dst, KRegister src) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); + assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(dst, knoreg, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x90); emit_int8((unsigned char)(0xC0 | encode)); } void Assembler::kmovql(KRegister dst, Address src) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); + assert(VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); @@ -2187,7 +2218,7 @@ void Assembler::kmovql(KRegister dst, Address src) { } void Assembler::kmovql(Address dst, KRegister src) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); + assert(VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); vex_prefix(dst, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); @@ -2196,46 +2227,53 @@ void Assembler::kmovql(Address dst, KRegister src) { } void Assembler::kmovql(KRegister dst, Register src) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); - VexSimdPrefix pre = !_legacy_mode_bw ? VEX_SIMD_F2 : VEX_SIMD_NONE; - InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_bw, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(dst, knoreg, src, pre, VEX_OPCODE_0F, &attributes); + assert(VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x92); emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::kmovql(Register dst, KRegister src) { + assert(VM_Version::supports_avx512bw(), ""); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0x93); + emit_int8((unsigned char)(0xC0 | encode)); +} + // This instruction produces ZF or CF flags void Assembler::kortestbl(KRegister src1, KRegister src2) { - NOT_LP64(assert(VM_Version::supports_avx512dq(), "")); + assert(VM_Version::supports_avx512dq(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(src1, knoreg, src2, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(src1->encoding(), 0, src2->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x98); emit_int8((unsigned char)(0xC0 | encode)); } // This instruction produces ZF or CF flags void Assembler::kortestwl(KRegister src1, KRegister src2) { - NOT_LP64(assert(VM_Version::supports_evex(), "")); + assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(src1, knoreg, src2, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(src1->encoding(), 0, src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x98); emit_int8((unsigned char)(0xC0 | encode)); } // This instruction produces ZF or CF flags void Assembler::kortestdl(KRegister src1, KRegister src2) { - NOT_LP64(assert(VM_Version::supports_avx512bw(), "")); + assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(src1, knoreg, src2, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(src1->encoding(), 0, src2->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x98); emit_int8((unsigned char)(0xC0 | encode)); } // This instruction produces ZF or CF flags void Assembler::kortestql(KRegister src1, KRegister src2) { - NOT_LP64(assert(VM_Version::supports_avx512bw(), "")); + assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = kreg_prefix_and_encode(src1, knoreg, src2, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(src1->encoding(), 0, src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x98); emit_int8((unsigned char)(0xC0 | encode)); } @@ -2375,7 +2413,7 @@ void Assembler::vmovdqu(Address dst, XMMRegister src) { // Move Unaligned EVEX enabled Vector (programmable : 8,16,32,64) void Assembler::evmovdqub(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x6F); emit_int8((unsigned char)(0xC0 | encode)); @@ -2395,7 +2433,7 @@ void Assembler::evmovdqub(Address dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); assert(src != xnoreg, "sanity"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(dst, 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x7F); @@ -2404,7 +2442,7 @@ void Assembler::evmovdqub(Address dst, XMMRegister src, int vector_len) { void Assembler::evmovdquw(XMMRegister dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); - InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x6F); emit_int8((unsigned char)(0xC0 | encode)); @@ -2424,7 +2462,7 @@ void Assembler::evmovdquw(Address dst, XMMRegister src, int vector_len) { assert(VM_Version::supports_evex(), ""); assert(src != xnoreg, "sanity"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(dst, 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x7F); @@ -3069,7 +3107,7 @@ void Assembler::packuswb(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x67); @@ -3078,7 +3116,7 @@ void Assembler::packuswb(XMMRegister dst, Address src) { void Assembler::packuswb(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x67); emit_int8((unsigned char)(0xC0 | encode)); @@ -3086,7 +3124,7 @@ void Assembler::packuswb(XMMRegister dst, XMMRegister src) { void Assembler::vpackuswb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "some form of AVX must be enabled"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x67); @@ -3128,7 +3166,7 @@ void Assembler::pcmpestri(XMMRegister dst, XMMRegister src, int imm8) { // In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst void Assembler::pcmpeqb(XMMRegister dst, XMMRegister src) { - NOT_LP64(assert(VM_Version::supports_sse2(), "")); + assert(VM_Version::supports_sse2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x74); @@ -3148,16 +3186,28 @@ void Assembler::vpcmpeqb(XMMRegister dst, XMMRegister nds, XMMRegister src, int // In this context, kdst is written the mask used to process the equal components void Assembler::evpcmpeqb(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512bw(), ""); - InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(kdst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x74); emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::evpcmpeqb(KRegister kdst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int dst_enc = kdst->encoding(); + vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x74); + emit_operand(as_Register(dst_enc), src); +} + // In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst void Assembler::pcmpeqw(XMMRegister dst, XMMRegister src) { - NOT_LP64(assert(VM_Version::supports_sse2(), "")); + assert(VM_Version::supports_sse2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x75); @@ -3177,16 +3227,28 @@ void Assembler::vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int // In this context, kdst is written the mask used to process the equal components void Assembler::evpcmpeqw(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len) { assert(VM_Version::supports_avx512bw(), ""); - InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(kdst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x75); emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::evpcmpeqw(KRegister kdst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_avx512bw(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int dst_enc = kdst->encoding(); + vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x75); + emit_operand(as_Register(dst_enc), src); +} + // In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst void Assembler::pcmpeqd(XMMRegister dst, XMMRegister src) { - NOT_LP64(assert(VM_Version::supports_sse2(), "")); + assert(VM_Version::supports_sse2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x76); @@ -3213,9 +3275,21 @@ void Assembler::evpcmpeqd(KRegister kdst, XMMRegister nds, XMMRegister src, int emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::evpcmpeqd(KRegister kdst, XMMRegister nds, Address src, int vector_len) { + assert(VM_Version::supports_evex(), ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_32bit); + int nds_enc = nds->is_valid() ? nds->encoding() : 0; + int dst_enc = kdst->encoding(); + vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x76); + emit_operand(as_Register(dst_enc), src); +} + // In this context, the dst vector contains the components that are equal, non equal components are zeroed in dst void Assembler::pcmpeqq(XMMRegister dst, XMMRegister src) { - NOT_LP64(assert(VM_Version::supports_sse4_1(), "")); + assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x29); @@ -3328,7 +3402,7 @@ void Assembler::pinsrw(XMMRegister dst, Register src, int imm8) { void Assembler::pmovzxbw(XMMRegister dst, Address src) { assert(VM_Version::supports_sse4_1(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_HVM, /* input_size_in_bits */ EVEX_NObit); simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x30); @@ -3337,7 +3411,7 @@ void Assembler::pmovzxbw(XMMRegister dst, Address src) { void Assembler::pmovzxbw(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_sse4_1(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x30); emit_int8((unsigned char)(0xC0 | encode)); @@ -3347,7 +3421,7 @@ void Assembler::vpmovzxbw(XMMRegister dst, Address src, int vector_len) { assert(VM_Version::supports_avx(), ""); InstructionMark im(this); assert(dst != xnoreg, "sanity"); - InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_HVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x30); @@ -3452,7 +3526,7 @@ void Assembler::prefix(Prefix p) { void Assembler::pshufb(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_ssse3(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x00); emit_int8((unsigned char)(0xC0 | encode)); @@ -3461,7 +3535,7 @@ void Assembler::pshufb(XMMRegister dst, XMMRegister src) { void Assembler::pshufb(XMMRegister dst, Address src) { assert(VM_Version::supports_ssse3(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x00); @@ -3495,7 +3569,7 @@ void Assembler::pshufd(XMMRegister dst, Address src, int mode) { void Assembler::pshuflw(XMMRegister dst, XMMRegister src, int mode) { assert(isByte(mode), "invalid value"); NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x70); emit_int8((unsigned char)(0xC0 | encode)); @@ -3507,7 +3581,7 @@ void Assembler::pshuflw(XMMRegister dst, Address src, int mode) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); simd_prefix(dst, xnoreg, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x70); @@ -4723,7 +4797,7 @@ void Assembler::vphaddd(XMMRegister dst, XMMRegister nds, XMMRegister src, int v void Assembler::paddb(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFC); emit_int8((unsigned char)(0xC0 | encode)); @@ -4731,7 +4805,7 @@ void Assembler::paddb(XMMRegister dst, XMMRegister src) { void Assembler::paddw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFD); emit_int8((unsigned char)(0xC0 | encode)); @@ -4771,7 +4845,7 @@ void Assembler::phaddd(XMMRegister dst, XMMRegister src) { void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFC); @@ -4780,7 +4854,7 @@ void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpaddw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFD); @@ -4808,7 +4882,7 @@ void Assembler::vpaddq(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); int nds_enc = nds->is_valid() ? nds->encoding() : 0; vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); @@ -4819,7 +4893,7 @@ void Assembler::vpaddb(XMMRegister dst, XMMRegister nds, Address src, int vector void Assembler::vpaddw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); int nds_enc = nds->is_valid() ? nds->encoding() : 0; vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); @@ -4851,7 +4925,7 @@ void Assembler::vpaddq(XMMRegister dst, XMMRegister nds, Address src, int vector void Assembler::psubb(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF8); emit_int8((unsigned char)(0xC0 | encode)); @@ -4859,7 +4933,7 @@ void Assembler::psubb(XMMRegister dst, XMMRegister src) { void Assembler::psubw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF9); emit_int8((unsigned char)(0xC0 | encode)); @@ -4882,7 +4956,7 @@ void Assembler::psubq(XMMRegister dst, XMMRegister src) { void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF8); @@ -4891,7 +4965,7 @@ void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpsubw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF9); @@ -4919,7 +4993,7 @@ void Assembler::vpsubq(XMMRegister dst, XMMRegister nds, XMMRegister src, int ve void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); int nds_enc = nds->is_valid() ? nds->encoding() : 0; vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); @@ -4930,7 +5004,7 @@ void Assembler::vpsubb(XMMRegister dst, XMMRegister nds, Address src, int vector void Assembler::vpsubw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); int nds_enc = nds->is_valid() ? nds->encoding() : 0; vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); @@ -4962,7 +5036,7 @@ void Assembler::vpsubq(XMMRegister dst, XMMRegister nds, Address src, int vector void Assembler::pmullw(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD5); emit_int8((unsigned char)(0xC0 | encode)); @@ -4978,7 +5052,7 @@ void Assembler::pmulld(XMMRegister dst, XMMRegister src) { void Assembler::vpmullw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int nds_enc = nds->is_valid() ? nds->encoding() : 0; int encode = vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD5); @@ -5006,7 +5080,7 @@ void Assembler::vpmullq(XMMRegister dst, XMMRegister nds, XMMRegister src, int v void Assembler::vpmullw(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); InstructionMark im(this); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); int nds_enc = nds->is_valid() ? nds->encoding() : 0; vex_prefix(src, nds_enc, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); @@ -5039,7 +5113,7 @@ void Assembler::vpmullq(XMMRegister dst, XMMRegister nds, Address src, int vecto // Shift packed integers left by specified number of bits. void Assembler::psllw(XMMRegister dst, int shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); // XMM6 is for /6 encoding: 66 0F 71 /6 ib int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); @@ -5069,7 +5143,7 @@ void Assembler::psllq(XMMRegister dst, int shift) { void Assembler::psllw(XMMRegister dst, XMMRegister shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF1); emit_int8((unsigned char)(0xC0 | encode)); @@ -5093,7 +5167,7 @@ void Assembler::psllq(XMMRegister dst, XMMRegister shift) { void Assembler::vpsllw(XMMRegister dst, XMMRegister src, int shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); // XMM6 is for /6 encoding: 66 0F 71 /6 ib int encode = vex_prefix_and_encode(xmm6->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); @@ -5124,7 +5198,7 @@ void Assembler::vpsllq(XMMRegister dst, XMMRegister src, int shift, int vector_l void Assembler::vpsllw(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xF1); emit_int8((unsigned char)(0xC0 | encode)); @@ -5149,7 +5223,7 @@ void Assembler::vpsllq(XMMRegister dst, XMMRegister src, XMMRegister shift, int // Shift packed integers logically right by specified number of bits. void Assembler::psrlw(XMMRegister dst, int shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); // XMM2 is for /2 encoding: 66 0F 71 /2 ib int encode = simd_prefix_and_encode(xmm2, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); @@ -5181,7 +5255,7 @@ void Assembler::psrlq(XMMRegister dst, int shift) { void Assembler::psrlw(XMMRegister dst, XMMRegister shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD1); emit_int8((unsigned char)(0xC0 | encode)); @@ -5205,7 +5279,7 @@ void Assembler::psrlq(XMMRegister dst, XMMRegister shift) { void Assembler::vpsrlw(XMMRegister dst, XMMRegister src, int shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); // XMM2 is for /2 encoding: 66 0F 71 /2 ib int encode = vex_prefix_and_encode(xmm2->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); @@ -5235,7 +5309,7 @@ void Assembler::vpsrlq(XMMRegister dst, XMMRegister src, int shift, int vector_l void Assembler::vpsrlw(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD1); emit_int8((unsigned char)(0xC0 | encode)); @@ -5260,7 +5334,7 @@ void Assembler::vpsrlq(XMMRegister dst, XMMRegister src, XMMRegister shift, int // Shift packed integers arithmetically right by specified number of bits. void Assembler::psraw(XMMRegister dst, int shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); // XMM4 is for /4 encoding: 66 0F 71 /4 ib int encode = simd_prefix_and_encode(xmm4, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); @@ -5280,7 +5354,7 @@ void Assembler::psrad(XMMRegister dst, int shift) { void Assembler::psraw(XMMRegister dst, XMMRegister shift) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = simd_prefix_and_encode(dst, dst, shift, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xE1); emit_int8((unsigned char)(0xC0 | encode)); @@ -5296,7 +5370,7 @@ void Assembler::psrad(XMMRegister dst, XMMRegister shift) { void Assembler::vpsraw(XMMRegister dst, XMMRegister src, int shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); // XMM4 is for /4 encoding: 66 0F 71 /4 ib int encode = vex_prefix_and_encode(xmm4->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x71); @@ -5316,7 +5390,7 @@ void Assembler::vpsrad(XMMRegister dst, XMMRegister src, int shift, int vector_l void Assembler::vpsraw(XMMRegister dst, XMMRegister src, XMMRegister shift, int vector_len) { assert(UseAVX > 0, "requires some form of AVX"); - InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), src->encoding(), shift->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xE1); emit_int8((unsigned char)(0xC0 | encode)); @@ -5706,7 +5780,7 @@ void Assembler::vpbroadcastd(XMMRegister dst, XMMRegister src) { // duplicate 2-bytes integer data from src into 16 locations in dest void Assembler::vpbroadcastw(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_avx2(), ""); - InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); + InstructionAttr attributes(AVX_256bit, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x79); emit_int8((unsigned char)(0xC0 | encode)); @@ -6573,18 +6647,6 @@ int Assembler::simd_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegis } } -int Assembler::kreg_prefix_and_encode(KRegister dst, KRegister nds, KRegister src, VexSimdPrefix pre, - VexOpcode opc, InstructionAttr *attributes) { - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - return vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), pre, opc, attributes); -} - -int Assembler::kreg_prefix_and_encode(KRegister dst, KRegister nds, Register src, VexSimdPrefix pre, - VexOpcode opc, InstructionAttr *attributes) { - int nds_enc = nds->is_valid() ? nds->encoding() : 0; - return vex_prefix_and_encode(dst->encoding(), nds_enc, src->encoding(), pre, opc, attributes); -} - void Assembler::cmppd(XMMRegister dst, XMMRegister nds, XMMRegister src, int cop, int vector_len) { assert(VM_Version::supports_avx(), ""); assert(!VM_Version::supports_evex(), ""); diff --git a/hotspot/src/cpu/x86/vm/assembler_x86.hpp b/hotspot/src/cpu/x86/vm/assembler_x86.hpp index a5f493905fc..4b6dcf4a028 100644 --- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp @@ -655,12 +655,6 @@ private: int simd_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes); - int kreg_prefix_and_encode(KRegister dst, KRegister nds, KRegister src, VexSimdPrefix pre, - VexOpcode opc, InstructionAttr *attributes); - - int kreg_prefix_and_encode(KRegister dst, KRegister nds, Register src, VexSimdPrefix pre, - VexOpcode opc, InstructionAttr *attributes); - // Helper functions for groups of instructions void emit_arith_b(int op1, int op2, Register dst, int imm8); @@ -1331,12 +1325,17 @@ private: void movddup(XMMRegister dst, XMMRegister src); + void kmovbl(KRegister dst, Register src); + void kmovbl(Register dst, KRegister src); void kmovwl(KRegister dst, Register src); + void kmovwl(Register dst, KRegister src); void kmovdl(KRegister dst, Register src); + void kmovdl(Register dst, KRegister src); void kmovql(KRegister dst, KRegister src); - void kmovql(KRegister dst, Register src); void kmovql(Address dst, KRegister src); void kmovql(KRegister dst, Address src); + void kmovql(KRegister dst, Register src); + void kmovql(Register dst, KRegister src); void kortestbl(KRegister dst, KRegister src); void kortestwl(KRegister dst, KRegister src); @@ -1521,14 +1520,17 @@ private: void pcmpeqb(XMMRegister dst, XMMRegister src); void vpcmpeqb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpcmpeqb(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len); + void evpcmpeqb(KRegister kdst, XMMRegister nds, Address src, int vector_len); void pcmpeqw(XMMRegister dst, XMMRegister src); void vpcmpeqw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpcmpeqw(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len); + void evpcmpeqw(KRegister kdst, XMMRegister nds, Address src, int vector_len); void pcmpeqd(XMMRegister dst, XMMRegister src); void vpcmpeqd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void evpcmpeqd(KRegister kdst, XMMRegister nds, XMMRegister src, int vector_len); + void evpcmpeqd(KRegister kdst, XMMRegister nds, Address src, int vector_len); void pcmpeqq(XMMRegister dst, XMMRegister src); void vpcmpeqq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 2ccee91a6cd..a916379ea36 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -7999,9 +7999,15 @@ void MacroAssembler::string_compare(Register str1, Register str2, XMMRegister vec1, int ae) { ShortBranchVerifier sbv(this); Label LENGTH_DIFF_LABEL, POP_LABEL, DONE_LABEL, WHILE_HEAD_LABEL; + Label COMPARE_WIDE_VECTORS_LOOP_FAILED; // used only _LP64 && AVX3 int stride, stride2, adr_stride, adr_stride1, adr_stride2; + int stride2x2 = 0x40; Address::ScaleFactor scale, scale1, scale2; + if (ae != StrIntrinsicNode::LL) { + stride2x2 = 0x20; + } + if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) { shrl(cnt2, 1); } @@ -8011,15 +8017,15 @@ void MacroAssembler::string_compare(Register str1, Register str2, movl(result, cnt1); subl(cnt1, cnt2); push(cnt1); - cmov32(Assembler::lessEqual, cnt2, result); + cmov32(Assembler::lessEqual, cnt2, result); // cnt2 = min(cnt1, cnt2) // Is the minimum length zero? testl(cnt2, cnt2); jcc(Assembler::zero, LENGTH_DIFF_LABEL); if (ae == StrIntrinsicNode::LL) { // Load first bytes - load_unsigned_byte(result, Address(str1, 0)); - load_unsigned_byte(cnt1, Address(str2, 0)); + load_unsigned_byte(result, Address(str1, 0)); // result = str1[0] + load_unsigned_byte(cnt1, Address(str2, 0)); // cnt1 = str2[0] } else if (ae == StrIntrinsicNode::UU) { // Load first characters load_unsigned_short(result, Address(str1, 0)); @@ -8060,7 +8066,10 @@ void MacroAssembler::string_compare(Register str1, Register str2, assert(UseSSE >= 4, "SSE4 must be enabled for SSE4.2 intrinsics to be available"); Label COMPARE_WIDE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_WIDE_TAIL, COMPARE_SMALL_STR; Label COMPARE_WIDE_VECTORS_LOOP, COMPARE_16_CHARS, COMPARE_INDEX_CHAR; + Label COMPARE_WIDE_VECTORS_LOOP_AVX2; Label COMPARE_TAIL_LONG; + Label COMPARE_WIDE_VECTORS_LOOP_AVX3; // used only _LP64 && AVX3 + int pcmpmask = 0x19; if (ae == StrIntrinsicNode::LL) { pcmpmask &= ~0x01; @@ -8123,11 +8132,40 @@ void MacroAssembler::string_compare(Register str1, Register str2, } subl(result, stride2); subl(cnt2, stride2); - jccb(Assembler::zero, COMPARE_WIDE_TAIL); + jcc(Assembler::zero, COMPARE_WIDE_TAIL); negptr(result); // In a loop, compare 16-chars (32-bytes) at once using (vpxor+vptest) bind(COMPARE_WIDE_VECTORS_LOOP); + +#ifdef _LP64 + if (VM_Version::supports_avx512vlbw()) { // trying 64 bytes fast loop + cmpl(cnt2, stride2x2); + jccb(Assembler::below, COMPARE_WIDE_VECTORS_LOOP_AVX2); + testl(cnt2, stride2x2-1); // cnt2 holds the vector count + jccb(Assembler::notZero, COMPARE_WIDE_VECTORS_LOOP_AVX2); // means we cannot subtract by 0x40 + + bind(COMPARE_WIDE_VECTORS_LOOP_AVX3); // the hottest loop + if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + evmovdquq(vec1, Address(str1, result, scale), Assembler::AVX_512bit); + evpcmpeqb(k7, vec1, Address(str2, result, scale), Assembler::AVX_512bit); // k7 == 11..11, if operands equal, otherwise k7 has some 0 + } else { + vpmovzxbw(vec1, Address(str1, result, scale1), Assembler::AVX_512bit); + evpcmpeqb(k7, vec1, Address(str2, result, scale2), Assembler::AVX_512bit); // k7 == 11..11, if operands equal, otherwise k7 has some 0 + } + kortestql(k7, k7); + jcc(Assembler::aboveEqual, COMPARE_WIDE_VECTORS_LOOP_FAILED); // miscompare + addptr(result, stride2x2); // update since we already compared at this addr + subl(cnt2, stride2x2); // and sub the size too + jccb(Assembler::notZero, COMPARE_WIDE_VECTORS_LOOP_AVX3); + + vpxor(vec1, vec1); + jmpb(COMPARE_WIDE_TAIL); + }//if (VM_Version::supports_avx512vlbw()) +#endif // _LP64 + + + bind(COMPARE_WIDE_VECTORS_LOOP_AVX2); if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { vmovdqu(vec1, Address(str1, result, scale)); vpxor(vec1, Address(str2, result, scale)); @@ -8136,7 +8174,7 @@ void MacroAssembler::string_compare(Register str1, Register str2, vpxor(vec1, Address(str2, result, scale2)); } vptest(vec1, vec1); - jccb(Assembler::notZero, VECTOR_NOT_EQUAL); + jcc(Assembler::notZero, VECTOR_NOT_EQUAL); addptr(result, stride2); subl(cnt2, stride2); jccb(Assembler::notZero, COMPARE_WIDE_VECTORS_LOOP); @@ -8151,7 +8189,7 @@ void MacroAssembler::string_compare(Register str1, Register str2, movl(result, stride2); movl(cnt2, result); negptr(result); - jmpb(COMPARE_WIDE_VECTORS_LOOP); + jmp(COMPARE_WIDE_VECTORS_LOOP_AVX2); // Identifies the mismatching (higher or lower)16-bytes in the 32-byte vectors. bind(VECTOR_NOT_EQUAL); @@ -8295,6 +8333,34 @@ void MacroAssembler::string_compare(Register str1, Register str2, } jmpb(DONE_LABEL); +#ifdef _LP64 + if (VM_Version::supports_avx512vlbw()) { + + bind(COMPARE_WIDE_VECTORS_LOOP_FAILED); + + kmovql(cnt1, k7); + notq(cnt1); + bsfq(cnt2, cnt1); + if (ae != StrIntrinsicNode::LL) { + // Divide diff by 2 to get number of chars + sarl(cnt2, 1); + } + addq(result, cnt2); + if (ae == StrIntrinsicNode::LL) { + load_unsigned_byte(cnt1, Address(str2, result)); + load_unsigned_byte(result, Address(str1, result)); + } else if (ae == StrIntrinsicNode::UU) { + load_unsigned_short(cnt1, Address(str2, result, scale)); + load_unsigned_short(result, Address(str1, result, scale)); + } else { + load_unsigned_short(cnt1, Address(str2, result, scale2)); + load_unsigned_byte(result, Address(str1, result, scale1)); + } + subl(result, cnt1); + jmpb(POP_LABEL); + }//if (VM_Version::supports_avx512vlbw()) +#endif // _LP64 + // Discard the stored length difference bind(POP_LABEL); pop(cnt1); @@ -8304,6 +8370,7 @@ void MacroAssembler::string_compare(Register str1, Register str2, if(ae == StrIntrinsicNode::UL) { negl(result); } + } // Search for Non-ASCII character (Negative byte value) in a byte array, diff --git a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp index 79b2a0f1db6..2ea8f1a49f0 100644 --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp @@ -189,7 +189,7 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ } // Save full ZMM registes(16..num_xmm_regs) base_addr = XSAVE_AREA_UPPERBANK; - int off = 0; + off = 0; int vector_len = Assembler::AVX_512bit; for (int n = 16; n < num_xmm_regs; n++) { __ evmovdqul(Address(rsp, base_addr+(off++*64)), as_XMMRegister(n), vector_len); @@ -199,7 +199,7 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_ if (VM_Version::supports_evex()) { // Save upper bank of ZMM registers(16..31) for double/float usage int base_addr = XSAVE_AREA_UPPERBANK; - int off = 0; + off = 0; for (int n = 16; n < num_xmm_regs; n++) { __ movsd(Address(rsp, base_addr+(off++*64)), as_XMMRegister(n)); } @@ -325,7 +325,7 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_ve assert(MaxVectorSize == 64, "only 512bit vectors are supported now"); } #else - assert(!save_vectors, "vectors are generated only by C2"); + assert(!restore_vectors, "vectors are generated only by C2"); #endif // On EVEX enabled targets everything is handled in pop fpu state diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp index 6298be79e33..b55d1bd2e9d 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp @@ -170,7 +170,7 @@ class StubGenerator: public StubCodeGenerator { // provide initial value for required masks if (UseAVX > 2) { __ movl(rbx, 0xffff); - __ kmovdl(k1, rbx); + __ kmovwl(k1, rbx); } // save and initialize %mxcsr @@ -798,7 +798,7 @@ class StubGenerator: public StubCodeGenerator { if (UseAVX > 2) { __ push(rbx); __ movl(rbx, 0xffff); - __ kmovdl(k1, rbx); + __ kmovwl(k1, rbx); __ pop(rbx); } // Copy 64-byte chunks diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index c704975870f..f86c6b88786 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -266,7 +266,7 @@ class StubGenerator: public StubCodeGenerator { __ movptr(r15_save, r15); if (UseAVX > 2) { __ movl(rbx, 0xffff); - __ kmovql(k1, rbx); + __ kmovwl(k1, rbx); } #ifdef _WIN64 int last_reg = 15; @@ -1350,7 +1350,7 @@ class StubGenerator: public StubCodeGenerator { Label L_end; if (UseAVX > 2) { __ movl(to, 0xffff); - __ kmovql(k1, to); + __ kmovwl(k1, to); } // Copy 64-bytes per iteration __ BIND(L_loop); @@ -1434,7 +1434,7 @@ class StubGenerator: public StubCodeGenerator { Label L_end; if (UseAVX > 2) { __ movl(to, 0xffff); - __ kmovql(k1, to); + __ kmovwl(k1, to); } // Copy 64-bytes per iteration __ BIND(L_loop); From ef1c3dc4ed614bcf7c8e9d6bb1d57015fc392ff7 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Mon, 7 Dec 2015 18:24:24 +0100 Subject: [PATCH 038/215] 8144850: C1: operator delete needs an implementation Reviewed-by: kvn --- hotspot/src/share/vm/c1/c1_LIRGenerator.hpp | 4 ++-- hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp index 47dd33df54e..9438d77288c 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp @@ -157,8 +157,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { private: void* operator new(size_t size) throw(); void* operator new[](size_t size) throw(); - void operator delete(void* p); - void operator delete[](void* p); + void operator delete(void* p) { ShouldNotReachHere(); } + void operator delete[](void* p) { ShouldNotReachHere(); } Compilation* _compilation; ciMethod* _method; // method that we are compiling diff --git a/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp b/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp index 608f39a9196..0552125b8dc 100644 --- a/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp +++ b/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp @@ -50,8 +50,8 @@ private: private: void* operator new(size_t size) throw(); void* operator new[](size_t size) throw(); - void operator delete(void* p); - void operator delete[](void* p); + void operator delete(void* p) { ShouldNotReachHere(); } + void operator delete[](void* p) { ShouldNotReachHere(); } IR *_ir; boolArray _used; From 0258eeaf71bd949460365c0ec0ddf4992e4a4acd Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Mon, 7 Dec 2015 17:05:03 -0800 Subject: [PATCH 039/215] 8144677: jprt.properties should allow creating a user specified testset with custom build flavors and build targets Made setting jprt.build.flavors and jprt.build.targets more flexible Reviewed-by: dholmes, mikael --- make/jprt.properties | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/make/jprt.properties b/make/jprt.properties index d7f3eedfd53..0f828b56621 100644 --- a/make/jprt.properties +++ b/make/jprt.properties @@ -69,9 +69,20 @@ jprt.fastdebugOpen.build.configure.args=${jprt.fastdebug.build.configure.args} - jprt.productOpen.build.configure.args=${jprt.product.build.configure.args} --enable-openjdk-only jprt.optimizedOpen.build.configure.args=${jprt.product.build.configure.args} --enable-openjdk-only -# Select build flavors and build targets -jprt.build.flavors=${my.is.hotspot.job ? ${my.build.flavors.hotspot} : ${my.build.flavors.default}} -jprt.build.targets=${my.is.hotspot.job ? ${my.build.targets.hotspot} : ${my.build.targets.default}} + +# hotspot testset has custom build flavors and build targets +my.jprt.testsetHasCustomBuildFlavors.hotspot=true +my.jprt.testsetHasCustomBuildTargets.hotspot=true + +# determine if the specified testset has custom build flavors or build targets +my.jprt.testsetHasCustomBuildFlavors=${my.jprt.testsetHasCustomBuildFlavors.${jprt.test.set}} +my.jprt.testsetHasCustomBuildTargets=${my.jprt.testsetHasCustomBuildTargets.${jprt.test.set}} + +# Select build flavors and build targets based on the specified testset +jprt.build.flavors=${my.jprt.testsetHasCustomBuildFlavors ? \ + ${my.build.flavors.${jprt.test.set}} : ${my.build.flavors.default}} +jprt.build.targets=${my.jprt.testsetHasCustomBuildTargets ? \ + ${my.build.targets.${jprt.test.set}} : ${my.build.targets.default}} # Select test targets - jprt default for jprt.test.set is "default" jprt.test.targets=${my.test.targets.${jprt.test.set}} From 5bfc44dca23a7c9c29b280595df85cbb0417ec16 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 8 Dec 2015 11:25:47 +0300 Subject: [PATCH 040/215] 7160052: GlyphVector.setGlyphPosition can throw an exception on valid input Reviewed-by: jdv, serb --- .../classes/sun/font/StandardGlyphVector.java | 8 ++- .../TestStandardGlyphVectorBug.java | 58 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/awt/font/GlyphVector/TestStandardGlyphVectorBug.java diff --git a/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java b/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java index 06abf9de163..69f1d4babc2 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java +++ b/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java @@ -445,13 +445,19 @@ public class StandardGlyphVector extends GlyphVector { } public void setGlyphPosition(int ix, Point2D pos) { + if (ix < 0 || ix > glyphs.length) { + throw new IndexOutOfBoundsException("ix = " + ix); + } + initPositions(); int ix2 = ix << 1; positions[ix2] = (float)pos.getX(); positions[ix2 + 1] = (float)pos.getY(); - clearCaches(ix); + if (ix < glyphs.length) { + clearCaches(ix); + } addFlags(FLAG_HAS_POSITION_ADJUSTMENTS); } diff --git a/jdk/test/java/awt/font/GlyphVector/TestStandardGlyphVectorBug.java b/jdk/test/java/awt/font/GlyphVector/TestStandardGlyphVectorBug.java new file mode 100644 index 00000000000..c4dbda40837 --- /dev/null +++ b/jdk/test/java/awt/font/GlyphVector/TestStandardGlyphVectorBug.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +import java.awt.Font; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; + +/** + * @test + * @bug 7160052 + * @run main TestStandardGlyphVectorBug + * @summary GlyphVector.setGlyphPosition should not throw an exception on valid input + */ +public class TestStandardGlyphVectorBug +{ + public static void main(String[] args) + { + Font defaultFont = new Font(null); + FontRenderContext defaultFrc = new FontRenderContext(new AffineTransform(), + true, true); + GlyphVector gv = defaultFont.createGlyphVector(defaultFrc, "test"); + + //this causes the bounds to be cached + //which is necessary to trigger the bug + gv.getGlyphLogicalBounds(0); + + //this correctly gets the position of the overall advance + Point2D glyphPosition = gv.getGlyphPosition(gv.getNumGlyphs()); + + // this sets the position of the overall advance, + // but also incorrectly tries to clear the bounds cache + // of a specific glyph indexed by the glyphIndex parameter + // even if the glyphIndex represents the overall advance + // (i.e. if glyphIndex == getNumGlyphs()) + gv.setGlyphPosition(gv.getNumGlyphs(), glyphPosition); + } +} From 555dd24642f5c4069d8782bcd95fd434b135cc18 Mon Sep 17 00:00:00 2001 From: Pavel Punegov Date: Wed, 9 Dec 2015 00:33:30 +0300 Subject: [PATCH 041/215] 8140667: CompilerControl: tests incorrectly set states for excluded methods Fix exclude command generation Reviewed-by: kvn --- .../mixed/RandomValidCommandsTest.java | 1 - .../scenario/AbstractCommandBuilder.java | 128 ++++++++++++++---- .../compilercontrol/share/scenario/State.java | 4 + 3 files changed, 103 insertions(+), 30 deletions(-) diff --git a/hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java b/hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java index 508963836e3..951789991f7 100644 --- a/hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java +++ b/hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java @@ -24,7 +24,6 @@ /* * @test * @bug 8137167 - * @ignore 8140667 * @summary Randomly generates valid commands with random types * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / * @build RandomValidCommandsTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox diff --git a/hotspot/test/compiler/compilercontrol/share/scenario/AbstractCommandBuilder.java b/hotspot/test/compiler/compilercontrol/share/scenario/AbstractCommandBuilder.java index 6a5b6342f47..0d78cadd8e0 100644 --- a/hotspot/test/compiler/compilercontrol/share/scenario/AbstractCommandBuilder.java +++ b/hotspot/test/compiler/compilercontrol/share/scenario/AbstractCommandBuilder.java @@ -33,6 +33,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.Callable; /** @@ -48,38 +49,12 @@ public abstract class AbstractCommandBuilder @Override public void add(CompileCommand command) { compileCommands.add(command); + CommandStateBuilder.getInstance().add(command); } @Override public Map getStates() { - Map states = new HashMap<>(); - for (CompileCommand compileCommand : compileCommands) { - if (compileCommand.isValid()) { - CompileCommand cc = new CompileCommand(compileCommand.command, - compileCommand.methodDescriptor, - /* CompileCommand option and file doesn't support - compiler setting */ - null, - compileCommand.type); - MethodDescriptor md = cc.methodDescriptor; - for (Pair> pair: METHODS) { - Executable exec = pair.first; - State state = states.getOrDefault(exec, new State()); - MethodDescriptor execDesc = new MethodDescriptor(exec); - // if executable matches regex then apply the state - if (execDesc.getCanonicalString().matches(md.getRegexp())) { - state.apply(cc); - } else { - if (cc.command == Command.COMPILEONLY) { - state.setC1Compilable(false); - state.setC2Compilable(false); - } - } - states.put(exec, state); - } - } - } - return states; + return CommandStateBuilder.getInstance().getStates(); } @Override @@ -89,7 +64,102 @@ public abstract class AbstractCommandBuilder @Override public boolean isValid() { - // CompileCommand ignores invalid items + // -XX:CompileCommand(File) ignores invalid items return true; } + + /* + * This is an internal class used to build states for commands given from + * options and a file. As all commands are added into a single set in + * CompilerOracle, we need a class that builds states in the same manner + */ + private static class CommandStateBuilder { + private static final CommandStateBuilder INSTANCE + = new CommandStateBuilder(); + private final List optionCommands = new ArrayList<>(); + private final List fileCommands = new ArrayList<>(); + + private CommandStateBuilder() { } + + public static CommandStateBuilder getInstance() { + return INSTANCE; + } + + public void add(CompileCommand command) { + switch (command.type) { + case OPTION: + optionCommands.add(command); + break; + case FILE: + fileCommands.add(command); + break; + default: + throw new Error("TESTBUG: wrong type: " + command.type); + } + } + + public Map getStates() { + List commandList = new ArrayList<>(); + commandList.addAll(optionCommands); + commandList.addAll(fileCommands); + Map states = new HashMap<>(); + for (Pair> pair : METHODS) { + Executable exec = pair.first; + State state = getState(commandList, states, exec); + states.put(exec, state); + } + return states; + } + + private State getState(List commandList, + Map states, Executable exec) { + State state = states.getOrDefault(exec, new State()); + MethodDescriptor execDesc = new MethodDescriptor(exec); + for (CompileCommand compileCommand : commandList) { + if (compileCommand.isValid()) { + // Create a copy without compiler set + CompileCommand cc = new CompileCommand( + compileCommand.command, + compileCommand.methodDescriptor, + /* CompileCommand option and file doesn't support + compiler setting */ + null, + compileCommand.type); + MethodDescriptor md = cc.methodDescriptor; + // if executable matches regex then apply the state + if (execDesc.getCanonicalString().matches(md.getRegexp())) { + if (cc.command == Command.COMPILEONLY + && !state.isCompilable()) { + /* if the method was already excluded it will not + be compilable again */ + } else { + state.apply(cc); + } + } + } + } + + /* + * Set compilation states for methods that don't match + * any compileonly command. Such methods should be excluded + * from compilation + */ + for (CompileCommand compileCommand : commandList) { + if (compileCommand.isValid() + && (compileCommand.command == Command.COMPILEONLY)) { + MethodDescriptor md = compileCommand.methodDescriptor; + if (!execDesc.getCanonicalString().matches(md.getRegexp()) + && (state.getCompilableOptional( + // no matter C1, C2 or both + Scenario.Compiler.C2).isPresent())) { + /* compileonly excludes only methods that haven't been + already set to be compilable or excluded */ + state.setC1Compilable(false); + state.setC2Compilable(false); + } + } + } + return state; + } + } } diff --git a/hotspot/test/compiler/compilercontrol/share/scenario/State.java b/hotspot/test/compiler/compilercontrol/share/scenario/State.java index b9a81984b69..82a46e7dc69 100644 --- a/hotspot/test/compiler/compilercontrol/share/scenario/State.java +++ b/hotspot/test/compiler/compilercontrol/share/scenario/State.java @@ -135,6 +135,10 @@ public class State { + "\nprint_inline " + printInline; } + public Optional getCompilableOptional(Scenario.Compiler compiler) { + return compile[compiler.ordinal()]; + } + public boolean isC1Compilable() { return compile[Scenario.Compiler.C1.ordinal()].orElse(true); } From a1bb5b8456cbfedbf39e56382005c120912fd36a Mon Sep 17 00:00:00 2001 From: Pavel Punegov Date: Wed, 9 Dec 2015 00:30:32 +0300 Subject: [PATCH 042/215] 8144933: CompilerControl: commandfile/ExcludeTest has incorrect jtreg run innotation Fix incorrect full test name Reviewed-by: kvn --- .../test/compiler/compilercontrol/commandfile/ExcludeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/test/compiler/compilercontrol/commandfile/ExcludeTest.java b/hotspot/test/compiler/compilercontrol/commandfile/ExcludeTest.java index b4843a7d930..0e5dc7948e0 100644 --- a/hotspot/test/compiler/compilercontrol/commandfile/ExcludeTest.java +++ b/hotspot/test/compiler/compilercontrol/commandfile/ExcludeTest.java @@ -30,7 +30,7 @@ * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main/othervm compiler.compilercontrol.commands.ExcludeTest + * @run main/othervm compiler.compilercontrol.commandfile.ExcludeTest */ package compiler.compilercontrol.commandfile; From 1f2a9c1407f43ad254bc467d24c17fbd7985d88c Mon Sep 17 00:00:00 2001 From: Jamsheed Mohammed Date: Wed, 9 Dec 2015 11:06:39 +0100 Subject: [PATCH 043/215] 6808665: Use486InstrsOnly aborts 32-bit VM The code supporting -XX:+/-Use486InstrsOnly was removed. Reviewed-by: dholmes, thartmann, vlivanov --- hotspot/src/cpu/x86/vm/globals_x86.hpp | 3 --- hotspot/src/cpu/x86/vm/vm_version_x86.cpp | 26 +++++++++++------------ 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/hotspot/src/cpu/x86/vm/globals_x86.hpp b/hotspot/src/cpu/x86/vm/globals_x86.hpp index 43c4cca5b2a..4c57e1b9a9f 100644 --- a/hotspot/src/cpu/x86/vm/globals_x86.hpp +++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp @@ -175,9 +175,6 @@ define_pd_global(bool, PreserveFramePointer, false); "Use RTM Xend instead of Xabort when lock busy") \ \ /* assembler */ \ - product(bool, Use486InstrsOnly, false, \ - "Use 80486 Compliant instruction subset") \ - \ product(bool, UseCountLeadingZerosInstruction, false, \ "Use count leading zeros instruction") \ \ diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp index eed88e81342..b13974f1e37 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.cpp @@ -473,23 +473,21 @@ void VM_Version::get_processor_features() { // i486 internal cache is both I&D and has a 16-byte line size _L1_data_cache_line_size = 16; - if (!Use486InstrsOnly) { - // Get raw processor info + // Get raw processor info - get_cpu_info_stub(&_cpuid_info); + get_cpu_info_stub(&_cpuid_info); - assert_is_initialized(); - _cpu = extended_cpu_family(); - _model = extended_cpu_model(); - _stepping = cpu_stepping(); + assert_is_initialized(); + _cpu = extended_cpu_family(); + _model = extended_cpu_model(); + _stepping = cpu_stepping(); - if (cpu_family() > 4) { // it supports CPUID - _cpuFeatures = feature_flags(); - // Logical processors are only available on P4s and above, - // and only if hyperthreading is available. - _logical_processors_per_package = logical_processor_count(); - _L1_data_cache_line_size = L1_line_size(); - } + if (cpu_family() > 4) { // it supports CPUID + _cpuFeatures = feature_flags(); + // Logical processors are only available on P4s and above, + // and only if hyperthreading is available. + _logical_processors_per_package = logical_processor_count(); + _L1_data_cache_line_size = L1_line_size(); } _supports_cx8 = supports_cmpxchg8(); From 4d4c7ad974ca451cedf0b3c3f31efcacc98234b6 Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Wed, 9 Dec 2015 14:54:40 +0100 Subject: [PATCH 044/215] 8143628: Fork sun.misc.Unsafe and jdk.internal.misc.Unsafe native method tables Reviewed-by: shade, dholmes, alanb, chegar, mchung, roland --- hotspot/src/share/vm/prims/nativeLookup.cpp | 7 +- hotspot/src/share/vm/prims/unsafe.cpp | 90 ++++++- ...dkInternalMiscUnsafeAccessTestBoolean.java | 135 ++++++++++ .../JdkInternalMiscUnsafeAccessTestByte.java | 172 ++++++++++++ .../JdkInternalMiscUnsafeAccessTestChar.java | 190 ++++++++++++++ ...JdkInternalMiscUnsafeAccessTestDouble.java | 172 ++++++++++++ .../JdkInternalMiscUnsafeAccessTestFloat.java | 172 ++++++++++++ .../JdkInternalMiscUnsafeAccessTestInt.java | 229 ++++++++++++++++ .../JdkInternalMiscUnsafeAccessTestLong.java | 229 ++++++++++++++++ ...JdkInternalMiscUnsafeAccessTestObject.java | 165 ++++++++++++ .../JdkInternalMiscUnsafeAccessTestShort.java | 190 ++++++++++++++ .../SunMiscUnsafeAccessTestBoolean.java | 135 ++++++++++ .../unsafe/SunMiscUnsafeAccessTestByte.java | 172 ++++++++++++ .../unsafe/SunMiscUnsafeAccessTestChar.java | 172 ++++++++++++ .../unsafe/SunMiscUnsafeAccessTestDouble.java | 172 ++++++++++++ .../unsafe/SunMiscUnsafeAccessTestFloat.java | 172 ++++++++++++ .../unsafe/SunMiscUnsafeAccessTestInt.java | 211 +++++++++++++++ .../unsafe/SunMiscUnsafeAccessTestLong.java | 211 +++++++++++++++ .../unsafe/SunMiscUnsafeAccessTestObject.java | 165 ++++++++++++ .../unsafe/SunMiscUnsafeAccessTestShort.java | 172 ++++++++++++ .../unsafe/X-UnsafeAccessTest.java.template | 247 ++++++++++++++++++ .../unsafe/generate-unsafe-access-tests.sh | 119 +++++++++ 22 files changed, 3690 insertions(+), 9 deletions(-) create mode 100644 hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java create mode 100644 hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java create mode 100644 hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java create mode 100644 hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java create mode 100644 hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java create mode 100644 hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java create mode 100644 hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java create mode 100644 hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java create mode 100644 hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java create mode 100644 hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestBoolean.java create mode 100644 hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestByte.java create mode 100644 hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestChar.java create mode 100644 hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestDouble.java create mode 100644 hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestFloat.java create mode 100644 hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestInt.java create mode 100644 hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestLong.java create mode 100644 hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestObject.java create mode 100644 hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestShort.java create mode 100644 hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template create mode 100644 hotspot/test/compiler/unsafe/generate-unsafe-access-tests.sh diff --git a/hotspot/src/share/vm/prims/nativeLookup.cpp b/hotspot/src/share/vm/prims/nativeLookup.cpp index fecef0a5055..5f693b46684 100644 --- a/hotspot/src/share/vm/prims/nativeLookup.cpp +++ b/hotspot/src/share/vm/prims/nativeLookup.cpp @@ -107,7 +107,8 @@ char* NativeLookup::long_jni_name(const methodHandle& method) { } extern "C" { - void JNICALL JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafecls); + void JNICALL JVM_RegisterJDKInternalMiscUnsafeMethods(JNIEnv *env, jclass unsafecls); + void JNICALL JVM_RegisterSunMiscUnsafeMethods(JNIEnv *env, jclass unsafecls); void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls); void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass); void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass); @@ -121,8 +122,8 @@ extern "C" { #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) static JNINativeMethod lookup_special_native_methods[] = { - { CC"Java_jdk_internal_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterUnsafeMethods) }, - { CC"Java_sun_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterUnsafeMethods) }, + { CC"Java_jdk_internal_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterJDKInternalMiscUnsafeMethods) }, + { CC"Java_sun_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterSunMiscUnsafeMethods) }, { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) }, { CC"Java_sun_misc_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) }, { CC"Java_sun_hotspot_WhiteBox_registerNatives", NULL, FN_PTR(JVM_RegisterWhiteBoxMethods) }, diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp index d2d1f0bb866..9d74cf1cf45 100644 --- a/hotspot/src/share/vm/prims/unsafe.cpp +++ b/hotspot/src/share/vm/prims/unsafe.cpp @@ -1227,8 +1227,76 @@ UNSAFE_END {CC "put" #Byte, CC "(" ADR#B ")V", FN_PTR(Unsafe_SetNative##Byte)} +static JNINativeMethod sun_misc_Unsafe_methods[] = { + {CC "getObject", CC "(" OBJ "J)" OBJ "", FN_PTR(Unsafe_GetObject)}, + {CC "putObject", CC "(" OBJ "J" OBJ ")V", FN_PTR(Unsafe_SetObject)}, + {CC "getObjectVolatile",CC "(" OBJ "J)" OBJ "", FN_PTR(Unsafe_GetObjectVolatile)}, + {CC "putObjectVolatile",CC "(" OBJ "J" OBJ ")V", FN_PTR(Unsafe_SetObjectVolatile)}, -static JNINativeMethod methods[] = { + {CC "getUncompressedObject", CC "(" ADR ")" OBJ, FN_PTR(Unsafe_GetUncompressedObject)}, + {CC "getJavaMirror", CC "(" ADR ")" CLS, FN_PTR(Unsafe_GetJavaMirror)}, + {CC "getKlassPointer", CC "(" OBJ ")" ADR, FN_PTR(Unsafe_GetKlassPointer)}, + + DECLARE_GETPUTOOP(Boolean, Z), + DECLARE_GETPUTOOP(Byte, B), + DECLARE_GETPUTOOP(Short, S), + DECLARE_GETPUTOOP(Char, C), + DECLARE_GETPUTOOP(Int, I), + DECLARE_GETPUTOOP(Long, J), + DECLARE_GETPUTOOP(Float, F), + DECLARE_GETPUTOOP(Double, D), + + DECLARE_GETPUTNATIVE(Byte, B), + DECLARE_GETPUTNATIVE(Short, S), + DECLARE_GETPUTNATIVE(Char, C), + DECLARE_GETPUTNATIVE(Int, I), + DECLARE_GETPUTNATIVE(Long, J), + DECLARE_GETPUTNATIVE(Float, F), + DECLARE_GETPUTNATIVE(Double, D), + + {CC "getAddress", CC "(" ADR ")" ADR, FN_PTR(Unsafe_GetNativeAddress)}, + {CC "putAddress", CC "(" ADR "" ADR ")V", FN_PTR(Unsafe_SetNativeAddress)}, + + {CC "allocateMemory", CC "(J)" ADR, FN_PTR(Unsafe_AllocateMemory)}, + {CC "reallocateMemory", CC "(" ADR "J)" ADR, FN_PTR(Unsafe_ReallocateMemory)}, + {CC "freeMemory", CC "(" ADR ")V", FN_PTR(Unsafe_FreeMemory)}, + + {CC "objectFieldOffset", CC "(" FLD ")J", FN_PTR(Unsafe_ObjectFieldOffset)}, + {CC "staticFieldOffset", CC "(" FLD ")J", FN_PTR(Unsafe_StaticFieldOffset)}, + {CC "staticFieldBase", CC "(" FLD ")" OBJ, FN_PTR(Unsafe_StaticFieldBaseFromField)}, + {CC "ensureClassInitialized",CC "(" CLS ")V", FN_PTR(Unsafe_EnsureClassInitialized)}, + {CC "arrayBaseOffset", CC "(" CLS ")I", FN_PTR(Unsafe_ArrayBaseOffset)}, + {CC "arrayIndexScale", CC "(" CLS ")I", FN_PTR(Unsafe_ArrayIndexScale)}, + {CC "addressSize", CC "()I", FN_PTR(Unsafe_AddressSize)}, + {CC "pageSize", CC "()I", FN_PTR(Unsafe_PageSize)}, + + {CC "defineClass", CC "(" DC_Args ")" CLS, FN_PTR(Unsafe_DefineClass)}, + {CC "allocateInstance", CC "(" CLS ")" OBJ, FN_PTR(Unsafe_AllocateInstance)}, + {CC "throwException", CC "(" THR ")V", FN_PTR(Unsafe_ThrowException)}, + {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 "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)}, + {CC "park", CC "(ZJ)V", FN_PTR(Unsafe_Park)}, + {CC "unpark", CC "(" OBJ ")V", FN_PTR(Unsafe_Unpark)}, + + {CC "getLoadAverage", CC "([DI)I", FN_PTR(Unsafe_Loadavg)}, + + {CC "copyMemory", CC "(" OBJ "J" OBJ "JJ)V", FN_PTR(Unsafe_CopyMemory)}, + {CC "setMemory", CC "(" OBJ "JJB)V", FN_PTR(Unsafe_SetMemory)}, + + {CC "defineAnonymousClass", CC "(" DAC_Args ")" CLS, FN_PTR(Unsafe_DefineAnonymousClass)}, + + {CC "shouldBeInitialized",CC "(" CLS ")Z", FN_PTR(Unsafe_ShouldBeInitialized)}, + + {CC "loadFence", CC "()V", FN_PTR(Unsafe_LoadFence)}, + {CC "storeFence", CC "()V", FN_PTR(Unsafe_StoreFence)}, + {CC "fullFence", CC "()V", FN_PTR(Unsafe_FullFence)}, +}; + +static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = { {CC "getObject", CC "(" OBJ "J)" OBJ "", FN_PTR(Unsafe_GetObject)}, {CC "putObject", CC "(" OBJ "J" OBJ ")V", FN_PTR(Unsafe_SetObject)}, {CC "getObjectVolatile",CC "(" OBJ "J)" OBJ "", FN_PTR(Unsafe_GetObjectVolatile)}, @@ -1316,17 +1384,27 @@ static JNINativeMethod methods[] = { #undef DECLARE_GETPUTNATIVE -// This one function is exported, used by NativeLookup. +// These two functions are exported, used by NativeLookup. // The Unsafe_xxx functions above are called only from the interpreter. // The optimizer looks at names and signatures to recognize // individual functions. -JVM_ENTRY(void, JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafeclass)) - UnsafeWrapper("JVM_RegisterUnsafeMethods"); +JVM_ENTRY(void, JVM_RegisterSunMiscUnsafeMethods(JNIEnv *env, jclass unsafeclass)) + UnsafeWrapper("JVM_RegisterSunMiscUnsafeMethods"); { ThreadToNativeFromVM ttnfv(thread); - int ok = env->RegisterNatives(unsafeclass, methods, sizeof(methods)/sizeof(JNINativeMethod)); - guarantee(ok == 0, "register unsafe natives"); + int ok = env->RegisterNatives(unsafeclass, sun_misc_Unsafe_methods, sizeof(sun_misc_Unsafe_methods)/sizeof(JNINativeMethod)); + guarantee(ok == 0, "register sun.misc.Unsafe natives"); + } +JVM_END + +JVM_ENTRY(void, JVM_RegisterJDKInternalMiscUnsafeMethods(JNIEnv *env, jclass unsafeclass)) + UnsafeWrapper("JVM_RegisterJDKInternalMiscUnsafeMethods"); + { + ThreadToNativeFromVM ttnfv(thread); + + int ok = env->RegisterNatives(unsafeclass, jdk_internal_misc_Unsafe_methods, sizeof(jdk_internal_misc_Unsafe_methods)/sizeof(JNINativeMethod)); + guarantee(ok == 0, "register jdk.internal.misc.Unsafe natives"); } JVM_END diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java new file mode 100644 index 00000000000..1f19d4c14da --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java @@ -0,0 +1,135 @@ +/* + * 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 8143628 + * @summary Test unsafe access for boolean + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestBoolean + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestBoolean + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestBoolean + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestBoolean + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestBoolean { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestBoolean.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestBoolean.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(boolean[].class); + int ascale = UNSAFE.arrayIndexScale(boolean[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static boolean static_v; + + boolean v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestBoolean t = new JdkInternalMiscUnsafeAccessTestBoolean(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + boolean[] array = new boolean[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putBoolean(base, offset, true); + boolean x = UNSAFE.getBoolean(base, offset); + assertEquals(x, true, "set boolean value"); + } + + // Volatile + { + UNSAFE.putBooleanVolatile(base, offset, false); + boolean x = UNSAFE.getBooleanVolatile(base, offset); + assertEquals(x, false, "putVolatile boolean value"); + } + + + + + } + +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java new file mode 100644 index 00000000000..a3ffa6fb8ab --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java @@ -0,0 +1,172 @@ +/* + * 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 8143628 + * @summary Test unsafe access for byte + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestByte + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestByte + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestByte + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestByte + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestByte { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestByte.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestByte.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); + int ascale = UNSAFE.arrayIndexScale(byte[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static byte static_v; + + byte v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestByte t = new JdkInternalMiscUnsafeAccessTestByte(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + byte[] array = new byte[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putByte(base, offset, (byte)1); + byte x = UNSAFE.getByte(base, offset); + assertEquals(x, (byte)1, "set byte value"); + } + + // Volatile + { + UNSAFE.putByteVolatile(base, offset, (byte)2); + byte x = UNSAFE.getByteVolatile(base, offset); + assertEquals(x, (byte)2, "putVolatile byte value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putByte(address, (byte)1); + byte x = UNSAFE.getByte(address); + assertEquals(x, (byte)1, "set byte value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java new file mode 100644 index 00000000000..b148aee5c8a --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java @@ -0,0 +1,190 @@ +/* + * 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 8143628 + * @summary Test unsafe access for char + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestChar + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestChar + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestChar + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestChar + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestChar { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestChar.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestChar.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(char[].class); + int ascale = UNSAFE.arrayIndexScale(char[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static char static_v; + + char v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestChar t = new JdkInternalMiscUnsafeAccessTestChar(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + char[] array = new char[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putChar(base, offset, 'a'); + char x = UNSAFE.getChar(base, offset); + assertEquals(x, 'a', "set char value"); + } + + // Volatile + { + UNSAFE.putCharVolatile(base, offset, 'b'); + char x = UNSAFE.getCharVolatile(base, offset); + assertEquals(x, 'b', "putVolatile char value"); + } + + + // Unaligned + { + UNSAFE.putCharUnaligned(base, offset, 'b'); + char x = UNSAFE.getCharUnaligned(base, offset); + assertEquals(x, 'b', "putUnaligned char value"); + } + + { + UNSAFE.putCharUnaligned(base, offset, 'a', true); + char x = UNSAFE.getCharUnaligned(base, offset, true); + assertEquals(x, 'a', "putUnaligned big endian char value"); + } + + { + UNSAFE.putCharUnaligned(base, offset, 'b', false); + char x = UNSAFE.getCharUnaligned(base, offset, false); + assertEquals(x, 'b', "putUnaligned little endian char value"); + } + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putChar(address, 'a'); + char x = UNSAFE.getChar(address); + assertEquals(x, 'a', "set char value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java new file mode 100644 index 00000000000..3ea637178ac --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java @@ -0,0 +1,172 @@ +/* + * 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 8143628 + * @summary Test unsafe access for double + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestDouble + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestDouble + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestDouble + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestDouble + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestDouble { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestDouble.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestDouble.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(double[].class); + int ascale = UNSAFE.arrayIndexScale(double[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static double static_v; + + double v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestDouble t = new JdkInternalMiscUnsafeAccessTestDouble(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + double[] array = new double[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putDouble(base, offset, 1.0d); + double x = UNSAFE.getDouble(base, offset); + assertEquals(x, 1.0d, "set double value"); + } + + // Volatile + { + UNSAFE.putDoubleVolatile(base, offset, 2.0d); + double x = UNSAFE.getDoubleVolatile(base, offset); + assertEquals(x, 2.0d, "putVolatile double value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putDouble(address, 1.0d); + double x = UNSAFE.getDouble(address); + assertEquals(x, 1.0d, "set double value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java new file mode 100644 index 00000000000..a2e313620fb --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java @@ -0,0 +1,172 @@ +/* + * 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 8143628 + * @summary Test unsafe access for float + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestFloat + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestFloat + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestFloat + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestFloat + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestFloat { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestFloat.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestFloat.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(float[].class); + int ascale = UNSAFE.arrayIndexScale(float[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static float static_v; + + float v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestFloat t = new JdkInternalMiscUnsafeAccessTestFloat(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + float[] array = new float[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putFloat(base, offset, 1.0f); + float x = UNSAFE.getFloat(base, offset); + assertEquals(x, 1.0f, "set float value"); + } + + // Volatile + { + UNSAFE.putFloatVolatile(base, offset, 2.0f); + float x = UNSAFE.getFloatVolatile(base, offset); + assertEquals(x, 2.0f, "putVolatile float value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putFloat(address, 1.0f); + float x = UNSAFE.getFloat(address); + assertEquals(x, 1.0f, "set float value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java new file mode 100644 index 00000000000..1ea024f1320 --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java @@ -0,0 +1,229 @@ +/* + * 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 8143628 + * @summary Test unsafe access for int + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestInt + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestInt + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestInt + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestInt + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestInt { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestInt.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestInt.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(int[].class); + int ascale = UNSAFE.arrayIndexScale(int[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static int static_v; + + int v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestInt t = new JdkInternalMiscUnsafeAccessTestInt(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + int[] array = new int[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putInt(base, offset, 1); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "set int value"); + } + + // Volatile + { + UNSAFE.putIntVolatile(base, offset, 2); + int x = UNSAFE.getIntVolatile(base, offset); + assertEquals(x, 2, "putVolatile int value"); + } + + // Lazy + { + UNSAFE.putOrderedInt(base, offset, 1); + int x = UNSAFE.getIntVolatile(base, offset); + assertEquals(x, 1, "putRelease int value"); + } + + // Unaligned + { + UNSAFE.putIntUnaligned(base, offset, 2); + int x = UNSAFE.getIntUnaligned(base, offset); + assertEquals(x, 2, "putUnaligned int value"); + } + + { + UNSAFE.putIntUnaligned(base, offset, 1, true); + int x = UNSAFE.getIntUnaligned(base, offset, true); + assertEquals(x, 1, "putUnaligned big endian int value"); + } + + { + UNSAFE.putIntUnaligned(base, offset, 2, false); + int x = UNSAFE.getIntUnaligned(base, offset, false); + assertEquals(x, 2, "putUnaligned little endian int value"); + } + + UNSAFE.putInt(base, offset, 1); + + // Compare + { + boolean r = UNSAFE.compareAndSwapInt(base, offset, 1, 2); + assertEquals(r, true, "success compareAndSwap int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "success compareAndSwap int value"); + } + + { + boolean r = UNSAFE.compareAndSwapInt(base, offset, 1, 3); + assertEquals(r, false, "failing compareAndSwap int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "failing compareAndSwap int value"); + } + + // Compare set and get + { + int o = UNSAFE.getAndSetInt(base, offset, 1); + assertEquals(o, 2, "getAndSet int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "getAndSet int value"); + } + + UNSAFE.putInt(base, offset, 1); + + // get and add, add and get + { + int o = UNSAFE.getAndAddInt(base, offset, 2); + assertEquals(o, 1, "getAndAdd int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1 + 2, "weakCompareAndSwapRelease int"); + } + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putInt(address, 1); + int x = UNSAFE.getInt(address); + assertEquals(x, 1, "set int value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java new file mode 100644 index 00000000000..0c5262019b1 --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java @@ -0,0 +1,229 @@ +/* + * 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 8143628 + * @summary Test unsafe access for long + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestLong + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestLong + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestLong + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestLong + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestLong { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestLong.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestLong.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(long[].class); + int ascale = UNSAFE.arrayIndexScale(long[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static long static_v; + + long v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestLong t = new JdkInternalMiscUnsafeAccessTestLong(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + long[] array = new long[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putLong(base, offset, 1L); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "set long value"); + } + + // Volatile + { + UNSAFE.putLongVolatile(base, offset, 2L); + long x = UNSAFE.getLongVolatile(base, offset); + assertEquals(x, 2L, "putVolatile long value"); + } + + // Lazy + { + UNSAFE.putOrderedLong(base, offset, 1L); + long x = UNSAFE.getLongVolatile(base, offset); + assertEquals(x, 1L, "putRelease long value"); + } + + // Unaligned + { + UNSAFE.putLongUnaligned(base, offset, 2L); + long x = UNSAFE.getLongUnaligned(base, offset); + assertEquals(x, 2L, "putUnaligned long value"); + } + + { + UNSAFE.putLongUnaligned(base, offset, 1L, true); + long x = UNSAFE.getLongUnaligned(base, offset, true); + assertEquals(x, 1L, "putUnaligned big endian long value"); + } + + { + UNSAFE.putLongUnaligned(base, offset, 2L, false); + long x = UNSAFE.getLongUnaligned(base, offset, false); + assertEquals(x, 2L, "putUnaligned little endian long value"); + } + + UNSAFE.putLong(base, offset, 1L); + + // Compare + { + boolean r = UNSAFE.compareAndSwapLong(base, offset, 1L, 2L); + assertEquals(r, true, "success compareAndSwap long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "success compareAndSwap long value"); + } + + { + boolean r = UNSAFE.compareAndSwapLong(base, offset, 1L, 3L); + assertEquals(r, false, "failing compareAndSwap long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "failing compareAndSwap long value"); + } + + // Compare set and get + { + long o = UNSAFE.getAndSetLong(base, offset, 1L); + assertEquals(o, 2L, "getAndSet long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "getAndSet long value"); + } + + UNSAFE.putLong(base, offset, 1L); + + // get and add, add and get + { + long o = UNSAFE.getAndAddLong(base, offset, 2L); + assertEquals(o, 1L, "getAndAdd long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L + 2L, "weakCompareAndSwapRelease long"); + } + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putLong(address, 1L); + long x = UNSAFE.getLong(address); + assertEquals(x, 1L, "set long value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java new file mode 100644 index 00000000000..c23cffd02ad --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java @@ -0,0 +1,165 @@ +/* + * 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 8143628 + * @summary Test unsafe access for Object + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestObject + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestObject + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestObject + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestObject + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestObject { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestObject.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestObject.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(Object[].class); + int ascale = UNSAFE.arrayIndexScale(Object[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static Object static_v; + + Object v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestObject t = new JdkInternalMiscUnsafeAccessTestObject(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + Object[] array = new Object[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putObject(base, offset, "foo"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "set Object value"); + } + + // Volatile + { + UNSAFE.putObjectVolatile(base, offset, "bar"); + Object x = UNSAFE.getObjectVolatile(base, offset); + assertEquals(x, "bar", "putVolatile Object value"); + } + + // Lazy + { + UNSAFE.putOrderedObject(base, offset, "foo"); + Object x = UNSAFE.getObjectVolatile(base, offset); + assertEquals(x, "foo", "putRelease Object value"); + } + + + UNSAFE.putObject(base, offset, "foo"); + + // Compare + { + boolean r = UNSAFE.compareAndSwapObject(base, offset, "foo", "bar"); + assertEquals(r, true, "success compareAndSwap Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "success compareAndSwap Object value"); + } + + { + boolean r = UNSAFE.compareAndSwapObject(base, offset, "foo", "baz"); + assertEquals(r, false, "failing compareAndSwap Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "failing compareAndSwap Object value"); + } + + // Compare set and get + { + Object o = UNSAFE.getAndSetObject(base, offset, "foo"); + assertEquals(o, "bar", "getAndSet Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "getAndSet Object value"); + } + + } + +} diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java new file mode 100644 index 00000000000..40a20789769 --- /dev/null +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java @@ -0,0 +1,190 @@ +/* + * 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 8143628 + * @summary Test unsafe access for short + * @modules java.base/jdk.internal.misc + * @run testng/othervm -Diters=100 -Xint JdkInternalMiscUnsafeAccessTestShort + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 JdkInternalMiscUnsafeAccessTestShort + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation JdkInternalMiscUnsafeAccessTestShort + * @run testng/othervm -Diters=20000 JdkInternalMiscUnsafeAccessTestShort + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class JdkInternalMiscUnsafeAccessTestShort { + static final int ITERS = Integer.getInteger("iters", 1); + + static final jdk.internal.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = JdkInternalMiscUnsafeAccessTestShort.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = JdkInternalMiscUnsafeAccessTestShort.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(short[].class); + int ascale = UNSAFE.arrayIndexScale(short[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static short static_v; + + short v; + + @Test + public void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestShort t = new JdkInternalMiscUnsafeAccessTestShort(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + short[] array = new short[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putShort(base, offset, (short)1); + short x = UNSAFE.getShort(base, offset); + assertEquals(x, (short)1, "set short value"); + } + + // Volatile + { + UNSAFE.putShortVolatile(base, offset, (short)2); + short x = UNSAFE.getShortVolatile(base, offset); + assertEquals(x, (short)2, "putVolatile short value"); + } + + + // Unaligned + { + UNSAFE.putShortUnaligned(base, offset, (short)2); + short x = UNSAFE.getShortUnaligned(base, offset); + assertEquals(x, (short)2, "putUnaligned short value"); + } + + { + UNSAFE.putShortUnaligned(base, offset, (short)1, true); + short x = UNSAFE.getShortUnaligned(base, offset, true); + assertEquals(x, (short)1, "putUnaligned big endian short value"); + } + + { + UNSAFE.putShortUnaligned(base, offset, (short)2, false); + short x = UNSAFE.getShortUnaligned(base, offset, false); + assertEquals(x, (short)2, "putUnaligned little endian short value"); + } + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putShort(address, (short)1); + short x = UNSAFE.getShort(address); + assertEquals(x, (short)1, "set short value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestBoolean.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestBoolean.java new file mode 100644 index 00000000000..976691c6735 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestBoolean.java @@ -0,0 +1,135 @@ +/* + * 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 8143628 + * @summary Test unsafe access for boolean + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestBoolean + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestBoolean + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestBoolean + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestBoolean + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestBoolean { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestBoolean.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestBoolean.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(boolean[].class); + int ascale = UNSAFE.arrayIndexScale(boolean[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static boolean static_v; + + boolean v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestBoolean t = new SunMiscUnsafeAccessTestBoolean(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + boolean[] array = new boolean[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putBoolean(base, offset, true); + boolean x = UNSAFE.getBoolean(base, offset); + assertEquals(x, true, "set boolean value"); + } + + // Volatile + { + UNSAFE.putBooleanVolatile(base, offset, false); + boolean x = UNSAFE.getBooleanVolatile(base, offset); + assertEquals(x, false, "putVolatile boolean value"); + } + + + + + } + +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestByte.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestByte.java new file mode 100644 index 00000000000..bdcab491316 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestByte.java @@ -0,0 +1,172 @@ +/* + * 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 8143628 + * @summary Test unsafe access for byte + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestByte + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestByte + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestByte + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestByte + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestByte { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestByte.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestByte.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); + int ascale = UNSAFE.arrayIndexScale(byte[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static byte static_v; + + byte v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestByte t = new SunMiscUnsafeAccessTestByte(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + byte[] array = new byte[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putByte(base, offset, (byte)1); + byte x = UNSAFE.getByte(base, offset); + assertEquals(x, (byte)1, "set byte value"); + } + + // Volatile + { + UNSAFE.putByteVolatile(base, offset, (byte)2); + byte x = UNSAFE.getByteVolatile(base, offset); + assertEquals(x, (byte)2, "putVolatile byte value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putByte(address, (byte)1); + byte x = UNSAFE.getByte(address); + assertEquals(x, (byte)1, "set byte value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestChar.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestChar.java new file mode 100644 index 00000000000..d7f56e31648 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestChar.java @@ -0,0 +1,172 @@ +/* + * 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 8143628 + * @summary Test unsafe access for char + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestChar + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestChar + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestChar + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestChar + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestChar { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestChar.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestChar.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(char[].class); + int ascale = UNSAFE.arrayIndexScale(char[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static char static_v; + + char v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestChar t = new SunMiscUnsafeAccessTestChar(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + char[] array = new char[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putChar(base, offset, 'a'); + char x = UNSAFE.getChar(base, offset); + assertEquals(x, 'a', "set char value"); + } + + // Volatile + { + UNSAFE.putCharVolatile(base, offset, 'b'); + char x = UNSAFE.getCharVolatile(base, offset); + assertEquals(x, 'b', "putVolatile char value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putChar(address, 'a'); + char x = UNSAFE.getChar(address); + assertEquals(x, 'a', "set char value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestDouble.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestDouble.java new file mode 100644 index 00000000000..e9c5624afe6 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestDouble.java @@ -0,0 +1,172 @@ +/* + * 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 8143628 + * @summary Test unsafe access for double + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestDouble + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestDouble + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestDouble + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestDouble + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestDouble { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestDouble.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestDouble.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(double[].class); + int ascale = UNSAFE.arrayIndexScale(double[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static double static_v; + + double v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestDouble t = new SunMiscUnsafeAccessTestDouble(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + double[] array = new double[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putDouble(base, offset, 1.0d); + double x = UNSAFE.getDouble(base, offset); + assertEquals(x, 1.0d, "set double value"); + } + + // Volatile + { + UNSAFE.putDoubleVolatile(base, offset, 2.0d); + double x = UNSAFE.getDoubleVolatile(base, offset); + assertEquals(x, 2.0d, "putVolatile double value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putDouble(address, 1.0d); + double x = UNSAFE.getDouble(address); + assertEquals(x, 1.0d, "set double value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestFloat.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestFloat.java new file mode 100644 index 00000000000..993c63339d8 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestFloat.java @@ -0,0 +1,172 @@ +/* + * 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 8143628 + * @summary Test unsafe access for float + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestFloat + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestFloat + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestFloat + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestFloat + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestFloat { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestFloat.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestFloat.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(float[].class); + int ascale = UNSAFE.arrayIndexScale(float[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static float static_v; + + float v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestFloat t = new SunMiscUnsafeAccessTestFloat(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + float[] array = new float[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putFloat(base, offset, 1.0f); + float x = UNSAFE.getFloat(base, offset); + assertEquals(x, 1.0f, "set float value"); + } + + // Volatile + { + UNSAFE.putFloatVolatile(base, offset, 2.0f); + float x = UNSAFE.getFloatVolatile(base, offset); + assertEquals(x, 2.0f, "putVolatile float value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putFloat(address, 1.0f); + float x = UNSAFE.getFloat(address); + assertEquals(x, 1.0f, "set float value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestInt.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestInt.java new file mode 100644 index 00000000000..8924cc168cd --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestInt.java @@ -0,0 +1,211 @@ +/* + * 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 8143628 + * @summary Test unsafe access for int + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestInt + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestInt + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestInt + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestInt + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestInt { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestInt.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestInt.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(int[].class); + int ascale = UNSAFE.arrayIndexScale(int[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static int static_v; + + int v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestInt t = new SunMiscUnsafeAccessTestInt(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + int[] array = new int[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putInt(base, offset, 1); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "set int value"); + } + + // Volatile + { + UNSAFE.putIntVolatile(base, offset, 2); + int x = UNSAFE.getIntVolatile(base, offset); + assertEquals(x, 2, "putVolatile int value"); + } + + // Lazy + { + UNSAFE.putOrderedInt(base, offset, 1); + int x = UNSAFE.getIntVolatile(base, offset); + assertEquals(x, 1, "putRelease int value"); + } + + + UNSAFE.putInt(base, offset, 1); + + // Compare + { + boolean r = UNSAFE.compareAndSwapInt(base, offset, 1, 2); + assertEquals(r, true, "success compareAndSwap int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "success compareAndSwap int value"); + } + + { + boolean r = UNSAFE.compareAndSwapInt(base, offset, 1, 3); + assertEquals(r, false, "failing compareAndSwap int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "failing compareAndSwap int value"); + } + + // Compare set and get + { + int o = UNSAFE.getAndSetInt(base, offset, 1); + assertEquals(o, 2, "getAndSet int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "getAndSet int value"); + } + + UNSAFE.putInt(base, offset, 1); + + // get and add, add and get + { + int o = UNSAFE.getAndAddInt(base, offset, 2); + assertEquals(o, 1, "getAndAdd int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1 + 2, "weakCompareAndSwapRelease int"); + } + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putInt(address, 1); + int x = UNSAFE.getInt(address); + assertEquals(x, 1, "set int value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestLong.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestLong.java new file mode 100644 index 00000000000..5999073a425 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestLong.java @@ -0,0 +1,211 @@ +/* + * 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 8143628 + * @summary Test unsafe access for long + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestLong + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestLong + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestLong + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestLong + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestLong { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestLong.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestLong.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(long[].class); + int ascale = UNSAFE.arrayIndexScale(long[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static long static_v; + + long v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestLong t = new SunMiscUnsafeAccessTestLong(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + long[] array = new long[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putLong(base, offset, 1L); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "set long value"); + } + + // Volatile + { + UNSAFE.putLongVolatile(base, offset, 2L); + long x = UNSAFE.getLongVolatile(base, offset); + assertEquals(x, 2L, "putVolatile long value"); + } + + // Lazy + { + UNSAFE.putOrderedLong(base, offset, 1L); + long x = UNSAFE.getLongVolatile(base, offset); + assertEquals(x, 1L, "putRelease long value"); + } + + + UNSAFE.putLong(base, offset, 1L); + + // Compare + { + boolean r = UNSAFE.compareAndSwapLong(base, offset, 1L, 2L); + assertEquals(r, true, "success compareAndSwap long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "success compareAndSwap long value"); + } + + { + boolean r = UNSAFE.compareAndSwapLong(base, offset, 1L, 3L); + assertEquals(r, false, "failing compareAndSwap long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "failing compareAndSwap long value"); + } + + // Compare set and get + { + long o = UNSAFE.getAndSetLong(base, offset, 1L); + assertEquals(o, 2L, "getAndSet long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "getAndSet long value"); + } + + UNSAFE.putLong(base, offset, 1L); + + // get and add, add and get + { + long o = UNSAFE.getAndAddLong(base, offset, 2L); + assertEquals(o, 1L, "getAndAdd long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L + 2L, "weakCompareAndSwapRelease long"); + } + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putLong(address, 1L); + long x = UNSAFE.getLong(address); + assertEquals(x, 1L, "set long value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestObject.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestObject.java new file mode 100644 index 00000000000..75fb599340b --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestObject.java @@ -0,0 +1,165 @@ +/* + * 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 8143628 + * @summary Test unsafe access for Object + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestObject + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestObject + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestObject + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestObject + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestObject { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestObject.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestObject.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(Object[].class); + int ascale = UNSAFE.arrayIndexScale(Object[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static Object static_v; + + Object v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestObject t = new SunMiscUnsafeAccessTestObject(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + Object[] array = new Object[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putObject(base, offset, "foo"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "set Object value"); + } + + // Volatile + { + UNSAFE.putObjectVolatile(base, offset, "bar"); + Object x = UNSAFE.getObjectVolatile(base, offset); + assertEquals(x, "bar", "putVolatile Object value"); + } + + // Lazy + { + UNSAFE.putOrderedObject(base, offset, "foo"); + Object x = UNSAFE.getObjectVolatile(base, offset); + assertEquals(x, "foo", "putRelease Object value"); + } + + + UNSAFE.putObject(base, offset, "foo"); + + // Compare + { + boolean r = UNSAFE.compareAndSwapObject(base, offset, "foo", "bar"); + assertEquals(r, true, "success compareAndSwap Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "success compareAndSwap Object value"); + } + + { + boolean r = UNSAFE.compareAndSwapObject(base, offset, "foo", "baz"); + assertEquals(r, false, "failing compareAndSwap Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "failing compareAndSwap Object value"); + } + + // Compare set and get + { + Object o = UNSAFE.getAndSetObject(base, offset, "foo"); + assertEquals(o, "bar", "getAndSet Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "getAndSet Object value"); + } + + } + +} diff --git a/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestShort.java b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestShort.java new file mode 100644 index 00000000000..ef4311483a6 --- /dev/null +++ b/hotspot/test/compiler/unsafe/SunMiscUnsafeAccessTestShort.java @@ -0,0 +1,172 @@ +/* + * 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 8143628 + * @summary Test unsafe access for short + * @modules java.base/sun.misc + * @run testng/othervm -Diters=100 -Xint SunMiscUnsafeAccessTestShort + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 SunMiscUnsafeAccessTestShort + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation SunMiscUnsafeAccessTestShort + * @run testng/othervm -Diters=20000 SunMiscUnsafeAccessTestShort + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class SunMiscUnsafeAccessTestShort { + static final int ITERS = Integer.getInteger("iters", 1); + + static final sun.misc.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = SunMiscUnsafeAccessTestShort.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = SunMiscUnsafeAccessTestShort.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset(short[].class); + int ascale = UNSAFE.arrayIndexScale(short[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static short static_v; + + short v; + + @Test + public void testFieldInstance() { + SunMiscUnsafeAccessTestShort t = new SunMiscUnsafeAccessTestShort(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + short[] array = new short[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.putShort(base, offset, (short)1); + short x = UNSAFE.getShort(base, offset); + assertEquals(x, (short)1, "set short value"); + } + + // Volatile + { + UNSAFE.putShortVolatile(base, offset, (short)2); + short x = UNSAFE.getShortVolatile(base, offset); + assertEquals(x, (short)2, "putVolatile short value"); + } + + + + + } + + static void testAccess(long address) { + // Plain + { + UNSAFE.putShort(address, (short)1); + short x = UNSAFE.getShort(address); + assertEquals(x, (short)1, "set short value"); + } + } +} diff --git a/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template b/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template new file mode 100644 index 00000000000..fcc74e325b0 --- /dev/null +++ b/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template @@ -0,0 +1,247 @@ +/* + * 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 8143628 + * @summary Test unsafe access for $type$ + * @modules java.base/$package$ + * @run testng/othervm -Diters=100 -Xint $Qualifier$UnsafeAccessTest$Type$ + * @run testng/othervm -Diters=20000 -XX:TieredStopAtLevel=1 $Qualifier$UnsafeAccessTest$Type$ + * @run testng/othervm -Diters=20000 -XX:-TieredCompilation $Qualifier$UnsafeAccessTest$Type$ + * @run testng/othervm -Diters=20000 $Qualifier$UnsafeAccessTest$Type$ + */ + +import org.testng.annotations.Test; + +import java.lang.reflect.Field; + +import static org.testng.Assert.*; + +public class $Qualifier$UnsafeAccessTest$Type$ { + static final int ITERS = Integer.getInteger("iters", 1); + + static final $package$.Unsafe UNSAFE; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static int ARRAY_OFFSET; + + static int ARRAY_SHIFT; + + static { + try { + Field f = $package$.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = ($package$.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + + try { + Field staticVField = $Qualifier$UnsafeAccessTest$Type$.class.getDeclaredField("static_v"); + STATIC_V_BASE = UNSAFE.staticFieldBase(staticVField); + STATIC_V_OFFSET = UNSAFE.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = $Qualifier$UnsafeAccessTest$Type$.class.getDeclaredField("v"); + V_OFFSET = UNSAFE.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = UNSAFE.arrayBaseOffset($type$[].class); + int ascale = UNSAFE.arrayIndexScale($type$[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static $type$ static_v; + + $type$ v; + + @Test + public void testFieldInstance() { + $Qualifier$UnsafeAccessTest$Type$ t = new $Qualifier$UnsafeAccessTest$Type$(); + for (int c = 0; c < ITERS; c++) { + testAccess(t, V_OFFSET); + } + } + + @Test + public void testFieldStatic() { + for (int c = 0; c < ITERS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + @Test + public void testArray() { + $type$[] array = new $type$[10]; + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + +#if[!Object] +#if[!boolean] + @Test + public void testArrayOffHeap() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess(null, (((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } + + @Test + public void testArrayOffHeapDirect() { + int size = 10; + long address = UNSAFE.allocateMemory(size << ARRAY_SHIFT); + try { + for (int c = 0; c < ITERS; c++) { + for (int i = 0; i < size; i++) { + testAccess((((long) i) << ARRAY_SHIFT) + address); + } + } + } finally { + UNSAFE.freeMemory(address); + } + } +#end[!boolean] +#end[!Object] + + static void testAccess(Object base, long offset) { + // Plain + { + UNSAFE.put$Type$(base, offset, $value1$); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "set $type$ value"); + } + + // Volatile + { + UNSAFE.put$Type$Volatile(base, offset, $value2$); + $type$ x = UNSAFE.get$Type$Volatile(base, offset); + assertEquals(x, $value2$, "putVolatile $type$ value"); + } + +#if[Ordered] + // Lazy + { + UNSAFE.putOrdered$Type$(base, offset, $value1$); + $type$ x = UNSAFE.get$Type$Volatile(base, offset); + assertEquals(x, $value1$, "putRelease $type$ value"); + } +#end[Ordered] + +#if[JdkInternalMisc] +#if[Unaligned] + // Unaligned + { + UNSAFE.put$Type$Unaligned(base, offset, $value2$); + $type$ x = UNSAFE.get$Type$Unaligned(base, offset); + assertEquals(x, $value2$, "putUnaligned $type$ value"); + } + + { + UNSAFE.put$Type$Unaligned(base, offset, $value1$, true); + $type$ x = UNSAFE.get$Type$Unaligned(base, offset, true); + assertEquals(x, $value1$, "putUnaligned big endian $type$ value"); + } + + { + UNSAFE.put$Type$Unaligned(base, offset, $value2$, false); + $type$ x = UNSAFE.get$Type$Unaligned(base, offset, false); + assertEquals(x, $value2$, "putUnaligned little endian $type$ value"); + } +#end[Unaligned] +#end[JdkInternalMisc] + +#if[CAS] + UNSAFE.put$Type$(base, offset, $value1$); + + // Compare + { + boolean r = UNSAFE.compareAndSwap$Type$(base, offset, $value1$, $value2$); + assertEquals(r, true, "success compareAndSwap $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "success compareAndSwap $type$ value"); + } + + { + boolean r = UNSAFE.compareAndSwap$Type$(base, offset, $value1$, $value3$); + assertEquals(r, false, "failing compareAndSwap $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "failing compareAndSwap $type$ value"); + } + + // Compare set and get + { + $type$ o = UNSAFE.getAndSet$Type$(base, offset, $value1$); + assertEquals(o, $value2$, "getAndSet $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "getAndSet $type$ value"); + } +#end[CAS] + +#if[AtomicAdd] + UNSAFE.put$Type$(base, offset, $value1$); + + // get and add, add and get + { + $type$ o = UNSAFE.getAndAdd$Type$(base, offset, $value2$); + assertEquals(o, $value1$, "getAndAdd $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$ + $value2$, "weakCompareAndSwapRelease $type$"); + } +#end[AtomicAdd] + } + +#if[!Object] +#if[!boolean] + static void testAccess(long address) { + // Plain + { + UNSAFE.put$Type$(address, $value1$); + $type$ x = UNSAFE.get$Type$(address); + assertEquals(x, $value1$, "set $type$ value"); + } + } +#end[!boolean] +#end[!Object] +} \ No newline at end of file diff --git a/hotspot/test/compiler/unsafe/generate-unsafe-access-tests.sh b/hotspot/test/compiler/unsafe/generate-unsafe-access-tests.sh new file mode 100644 index 00000000000..fc4f7f47ee1 --- /dev/null +++ b/hotspot/test/compiler/unsafe/generate-unsafe-access-tests.sh @@ -0,0 +1,119 @@ +#!/bin/bash + +# +# 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. +# + +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 bbc34efe2612f099073d5b0eb119a2f253cc2c47 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Wed, 9 Dec 2015 22:57:52 +0100 Subject: [PATCH 045/215] 8144944: JVMCI compiler initialization can happen on different thread than JVMCI initialization Reviewed-by: twisti --- .../src/jdk/vm/ci/inittimer/InitTimer.java | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java index 608285e7e92..921b537bfb1 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.inittimer/src/jdk/vm/ci/inittimer/InitTimer.java @@ -22,6 +22,8 @@ */ package jdk.vm.ci.inittimer; +import java.util.concurrent.atomic.AtomicInteger; + /** * A facility for timing a step in the runtime initialization sequence. This is independent from all * other JVMCI code so as to not perturb the initialization sequence. It is enabled by setting the @@ -32,18 +34,26 @@ public final class InitTimer implements AutoCloseable { final long start; private InitTimer(String name) { + int n = nesting.getAndIncrement(); + if (n == 0) { + initializingThread = Thread.currentThread(); + System.out.println("INITIALIZING THREAD: " + initializingThread); + } else { + assert Thread.currentThread() == initializingThread : Thread.currentThread() + " != " + initializingThread; + } this.name = name; this.start = System.currentTimeMillis(); - System.out.println("START: " + SPACES.substring(0, timerDepth * 2) + name); - assert Thread.currentThread() == initializingThread : Thread.currentThread() + " != " + initializingThread; - timerDepth++; + System.out.println("START: " + SPACES.substring(0, n * 2) + name); } @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "only the initializing thread accesses this field") public void close() { final long end = System.currentTimeMillis(); - timerDepth--; - System.out.println(" DONE: " + SPACES.substring(0, timerDepth * 2) + name + " [" + (end - start) + " ms]"); + int n = nesting.decrementAndGet(); + System.out.println(" DONE: " + SPACES.substring(0, n * 2) + name + " [" + (end - start) + " ms]"); + if (n == 0) { + initializingThread = null; + } } public static InitTimer timer(String name) { @@ -59,19 +69,11 @@ public final class InitTimer implements AutoCloseable { */ private static final boolean ENABLED = Boolean.getBoolean("jvmci.inittimer") || Boolean.getBoolean("jvmci.runtime.TimeInit"); - public static int timerDepth = 0; + public static final AtomicInteger nesting = ENABLED ? new AtomicInteger() : null; public static final String SPACES = " "; /** - * Used to assert the invariant that all initialization happens on the same thread. + * Used to assert the invariant that all related initialization happens on the same thread. */ - public static final Thread initializingThread; - static { - if (ENABLED) { - initializingThread = Thread.currentThread(); - System.out.println("INITIALIZING THREAD: " + initializingThread); - } else { - initializingThread = null; - } - } + public static Thread initializingThread; } From 7b54819d3ee2fc6f34b22fcedd7956923685845a Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Wed, 9 Dec 2015 13:41:04 +0100 Subject: [PATCH 046/215] 8144601: Premature assert in directive inline parsing Break after first fail Reviewed-by: roland --- hotspot/src/share/vm/compiler/directivesParser.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/hotspot/src/share/vm/compiler/directivesParser.cpp b/hotspot/src/share/vm/compiler/directivesParser.cpp index e916b536dd2..7c2b15404ac 100644 --- a/hotspot/src/share/vm/compiler/directivesParser.cpp +++ b/hotspot/src/share/vm/compiler/directivesParser.cpp @@ -379,11 +379,12 @@ bool DirectivesParser::set_option(JSON_TYPE t, JSON_VAL* v) { const char* error_msg = NULL; if (current_directiveset == NULL) { - if (!current_directive->_c1_store->parse_and_add_inline(s, error_msg)) { - assert (error_msg != NULL, "Must have valid error message"); - error(VALUE_ERROR, "Method pattern error: %s", error_msg); - } - if (!current_directive->_c2_store->parse_and_add_inline(s, error_msg)) { + if (current_directive->_c1_store->parse_and_add_inline(s, error_msg)) { + if (!current_directive->_c2_store->parse_and_add_inline(s, error_msg)) { + assert (error_msg != NULL, "Must have valid error message"); + error(VALUE_ERROR, "Method pattern error: %s", error_msg); + } + } else { assert (error_msg != NULL, "Must have valid error message"); error(VALUE_ERROR, "Method pattern error: %s", error_msg); } From afeb87ddd8adffe47d5ce5b0a18d9122329bfbbc Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Thu, 10 Dec 2015 14:51:53 +0300 Subject: [PATCH 047/215] 8144935: C2: safepoint is pruned from a non-counted loop Reviewed-by: roland --- hotspot/src/share/vm/opto/loopnode.cpp | 19 ++++++++++++++++--- hotspot/src/share/vm/opto/node.cpp | 11 +++++++++++ hotspot/src/share/vm/opto/node.hpp | 1 + 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp index db0b3c83c84..ac82a605303 100644 --- a/hotspot/src/share/vm/opto/loopnode.cpp +++ b/hotspot/src/share/vm/opto/loopnode.cpp @@ -1818,10 +1818,9 @@ void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) { } void IdealLoopTree::remove_safepoints(PhaseIdealLoop* phase, bool keep_one) { - // Look for a safepoint on the idom-path. Node* keep = NULL; if (keep_one) { - // Keep one if possible + // Look for a safepoint on the idom-path. for (Node* i = tail(); i != _head; i = phase->idom(i)) { if (i->Opcode() == Op_SafePoint && phase->get_loop(i) == this) { keep = i; @@ -1830,9 +1829,14 @@ void IdealLoopTree::remove_safepoints(PhaseIdealLoop* phase, bool keep_one) { } } + // Don't remove any safepoints if it is requested to keep a single safepoint and + // no safepoint was found on idom-path. It is not safe to remove any safepoint + // in this case since there's no safepoint dominating all paths in the loop body. + bool prune = !keep_one || keep != NULL; + // Delete other safepoints in this loop. Node_List* sfpts = _safepts; - if (sfpts != NULL) { + if (prune && sfpts != NULL) { assert(keep == NULL || keep->Opcode() == Op_SafePoint, "not safepoint"); for (uint i = 0; i < sfpts->size(); i++) { Node* n = sfpts->at(i); @@ -1925,6 +1929,15 @@ void IdealLoopTree::dump_head( ) const { if (cl->is_main_loop()) tty->print(" main"); if (cl->is_post_loop()) tty->print(" post"); } + if (_has_call) tty->print(" has_call"); + if (_has_sfpt) tty->print(" has_sfpt"); + if (_rce_candidate) tty->print(" rce"); + if (_safepts != NULL && _safepts->size() > 0) { + tty->print(" sfpts={"); _safepts->dump_simple(); tty->print(" }"); + } + if (_required_safept != NULL && _required_safept->size() > 0) { + tty->print(" req={"); _required_safept->dump_simple(); tty->print(" }"); + } tty->cr(); } diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp index dc91ef3e471..ac093690bc5 100644 --- a/hotspot/src/share/vm/opto/node.cpp +++ b/hotspot/src/share/vm/opto/node.cpp @@ -2365,6 +2365,17 @@ void Node_List::dump() const { #endif } +void Node_List::dump_simple() const { +#ifndef PRODUCT + for( uint i = 0; i < _cnt; i++ ) + if( _nodes[i] ) { + tty->print(" %d", _nodes[i]->_idx); + } else { + tty->print(" NULL"); + } +#endif +} + //============================================================================= //------------------------------remove----------------------------------------- void Unique_Node_List::remove( Node *n ) { diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp index 0d29b85b45a..d737f537868 100644 --- a/hotspot/src/share/vm/opto/node.hpp +++ b/hotspot/src/share/vm/opto/node.hpp @@ -1442,6 +1442,7 @@ public: void clear() { _cnt = 0; Node_Array::clear(); } // retain storage uint size() const { return _cnt; } void dump() const; + void dump_simple() const; }; //------------------------------Unique_Node_List------------------------------- From e56a7de478a319879d8a9cb3dd2a90799580491d Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Thu, 10 Dec 2015 14:51:54 +0300 Subject: [PATCH 048/215] 8145026: compiler/jsr292/NonInlinedCall/RedefineTest.java fails with: java.lang.NullPointerException in ClassFileInstaller.main Reviewed-by: roland --- hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java | 1 - hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java | 6 ++---- hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java | 6 ++---- .../test/compiler/jsr292/NonInlinedCall/RedefineTest.java | 6 ++---- 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java b/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java index 415f0b6b903..70665d5f604 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java @@ -22,7 +22,6 @@ */ import java.io.File; import java.io.PrintStream; -import java.lang.instrument.Instrumentation; import java.util.Arrays; public class Agent { diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java index 8be925b00d6..49ce05490fd 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java @@ -24,8 +24,8 @@ /* * @test * @bug 8072008 - * @library /testlibrary /../../test/lib - * @build GCTest NonInlinedReinvoker + * @library /testlibrary /test/lib + * @compile GCTest.java NonInlinedReinvoker.java * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * java.lang.invoke.GCTest @@ -40,10 +40,8 @@ package java.lang.invoke; import sun.hotspot.WhiteBox; - import jdk.internal.vm.annotation.DontInline; import jdk.internal.vm.annotation.Stable; - import java.lang.ref.*; import static jdk.test.lib.Asserts.*; diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java index 8ab6031b575..72a521d480d 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java @@ -24,8 +24,8 @@ /* * @test * @bug 8072008 - * @library /testlibrary /../../test/lib - * @build InvokeTest NonInlinedReinvoker + * @library /testlibrary /test/lib + * @compile InvokeTest.java NonInlinedReinvoker.java * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * java.lang.invoke.InvokeTest @@ -43,9 +43,7 @@ package java.lang.invoke; import sun.hotspot.WhiteBox; - import jdk.internal.vm.annotation.DontInline; - import static jdk.test.lib.Asserts.*; public class InvokeTest { diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java index 2da0f4bd70b..884295cf77e 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java @@ -24,8 +24,8 @@ /* * @test * @bug 8072008 - * @library /testlibrary /../../test/lib - * @build RedefineTest Agent + * @library /testlibrary /test/lib + * @compile -XDignore.symbol.file RedefineTest.java Agent.java * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * java.lang.invoke.RedefineTest @@ -42,10 +42,8 @@ package java.lang.invoke; import sun.hotspot.WhiteBox; import sun.misc.Unsafe; - import jdk.internal.org.objectweb.asm.*; import jdk.internal.vm.annotation.DontInline; - import java.lang.instrument.ClassDefinition; import java.lang.instrument.Instrumentation; From 1a4c3a752dfa45eb6f09922077cb99941dced229 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Fri, 11 Dec 2015 15:03:11 +0300 Subject: [PATCH 049/215] 8145137: Incorrect call signature can be used in nmethod::preserve_callee_argument_oops Reviewed-by: roland, jrose --- hotspot/src/share/vm/code/nmethod.cpp | 21 ++++++++++++++++++- hotspot/src/share/vm/code/nmethod.hpp | 1 + .../src/share/vm/runtime/sharedRuntime.cpp | 5 +---- .../jsr292/NonInlinedCall/InvokeTest.java | 16 +++++++------- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 18625bcbbe3..a2f256a680d 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -2332,11 +2332,22 @@ bool nmethod::detect_scavenge_root_oops() { void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { #ifndef SHARK if (method() != NULL && !method()->is_native()) { - SimpleScopeDesc ssd(this, fr.pc()); + address pc = fr.pc(); + SimpleScopeDesc ssd(this, pc); Bytecode_invoke call(ssd.method(), ssd.bci()); bool has_receiver = call.has_receiver(); bool has_appendix = call.has_appendix(); Symbol* signature = call.signature(); + + // The method attached by JIT-compilers should be used, if present. + // Bytecode can be inaccurate in such case. + Method* callee = attached_method_before_pc(pc); + if (callee != NULL) { + has_receiver = !(callee->access_flags().is_static()); + has_appendix = false; + signature = callee->signature(); + } + fr.oops_compiled_arguments_do(signature, has_receiver, has_appendix, reg_map, f); } #endif // !SHARK @@ -3526,3 +3537,11 @@ Method* nmethod::attached_method(address call_instr) { return NULL; // not found } +Method* nmethod::attached_method_before_pc(address pc) { + if (NativeCall::is_call_before(pc)) { + NativeCall* ncall = nativeCall_before(pc); + return attached_method(ncall->instruction_address()); + } + return NULL; // not a call +} + diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 5f9b1aa320f..2305f51bc24 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -512,6 +512,7 @@ class nmethod : public CodeBlob { void copy_values(GrowableArray* metadata); Method* attached_method(address call_pc); + Method* attached_method_before_pc(address pc); // Relocation support private: diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index a79ae71fbc6..02c8dc656d5 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -1078,10 +1078,7 @@ methodHandle SharedRuntime::extract_attached_method(vframeStream& vfst) { address pc = vfst.frame_pc(); { // Get call instruction under lock because another thread may be busy patching it. MutexLockerEx ml_patch(Patching_lock, Mutex::_no_safepoint_check_flag); - if (NativeCall::is_call_before(pc)) { - NativeCall* ncall = nativeCall_before(pc); - return caller_nm->attached_method(ncall->instruction_address()); - } + return caller_nm->attached_method_before_pc(pc); } return NULL; } diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java index 72a521d480d..02bdef91a10 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java @@ -74,23 +74,23 @@ public class InvokeTest { } static class T implements I { - @DontInline public Class f1() { if (doDeopt) WB.deoptimize(); return T.class; } - @DontInline public static Class f2() { if (doDeopt) WB.deoptimize(); return T.class; } - @DontInline private Class f4() { if (doDeopt) WB.deoptimize(); return T.class; } + @DontInline public Class f1() { if (doDeopt) WB.deoptimizeAll(); return T.class; } + @DontInline public static Class f2() { if (doDeopt) WB.deoptimizeAll(); return T.class; } + @DontInline private Class f4() { if (doDeopt) WB.deoptimizeAll(); return T.class; } } static class P1 extends T { - @DontInline public Class f1() { if (doDeopt) WB.deoptimize(); return P1.class; } - @DontInline public Class f3() { if (doDeopt) WB.deoptimize(); return P1.class; } + @DontInline public Class f1() { if (doDeopt) WB.deoptimizeAll(); return P1.class; } + @DontInline public Class f3() { if (doDeopt) WB.deoptimizeAll(); return P1.class; } } static class P2 extends T { - @DontInline public Class f1() { if (doDeopt) WB.deoptimize(); return P2.class; } - @DontInline public Class f3() { if (doDeopt) WB.deoptimize(); return P2.class; } + @DontInline public Class f1() { if (doDeopt) WB.deoptimizeAll(); return P2.class; } + @DontInline public Class f3() { if (doDeopt) WB.deoptimizeAll(); return P2.class; } } static interface I { - @DontInline default Class f3() { if (doDeopt) WB.deoptimize(); return I.class; } + @DontInline default Class f3() { if (doDeopt) WB.deoptimizeAll(); return I.class; } } @DontInline From 2b4403dc8837df2edb09a294c6cd0f902a6dba7c Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Mon, 14 Dec 2015 10:22:19 +0100 Subject: [PATCH 050/215] 8145300: ppc64: fix port of "8072008: Emit direct call instead of linkTo* for recursive indy/MH.invoke* calls" Reviewed-by: simonis --- hotspot/src/cpu/ppc/vm/ppc.ad | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index 781b4038229..682474c05a3 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -3486,6 +3486,7 @@ encode %{ call->_jvmadj = _jvmadj; call->_in_rms = _in_rms; call->_nesting = _nesting; + call->_override_symbolic_info = _override_symbolic_info; // New call needs all inputs of old call. // Req... From c2221a88e819436b7c973942367eb7eeabc354e7 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Mon, 14 Dec 2015 15:53:48 +0000 Subject: [PATCH 051/215] 8145320: Create unsafe_arraycopy and generic_arraycopy for AArch64 Reviewed-by: kvn --- .../cpu/aarch64/vm/stubGenerator_aarch64.cpp | 364 +++++++++++++++++- 1 file changed, 355 insertions(+), 9 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp index 2eb119125f2..30b42c0634c 100644 --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp @@ -958,8 +958,8 @@ class StubGenerator: public StubCodeGenerator { const Register t0 = r3, t1 = r4; if (is_backwards) { - __ lea(s, Address(s, count, Address::uxtw(exact_log2(-step)))); - __ lea(d, Address(d, count, Address::uxtw(exact_log2(-step)))); + __ lea(s, Address(s, count, Address::lsl(exact_log2(-step)))); + __ lea(d, Address(d, count, Address::lsl(exact_log2(-step)))); } Label done, tail; @@ -1051,10 +1051,10 @@ class StubGenerator: public StubCodeGenerator { __ cmp(rscratch2, count); __ br(Assembler::HS, end); if (size == (size_t)wordSize) { - __ ldr(temp, Address(a, rscratch2, Address::uxtw(exact_log2(size)))); + __ ldr(temp, Address(a, rscratch2, Address::lsl(exact_log2(size)))); __ verify_oop(temp); } else { - __ ldrw(r16, Address(a, rscratch2, Address::uxtw(exact_log2(size)))); + __ ldrw(r16, Address(a, rscratch2, Address::lsl(exact_log2(size)))); __ decode_heap_oop(temp); // calls verify_oop } __ add(rscratch2, rscratch2, size); @@ -1087,12 +1087,14 @@ class StubGenerator: public StubCodeGenerator { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", name); address start = __ pc(); + __ enter(); + if (entry != NULL) { *entry = __ pc(); // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) BLOCK_COMMENT("Entry:"); } - __ enter(); + if (is_oop) { __ push(RegSet::of(d, count), sp); // no registers are destroyed by this call @@ -1104,10 +1106,11 @@ class StubGenerator: public StubCodeGenerator { if (VerifyOops) verify_oop_array(size, d, count, r16); __ sub(count, count, 1); // make an inclusive end pointer - __ lea(count, Address(d, count, Address::uxtw(exact_log2(size)))); + __ lea(count, Address(d, count, Address::lsl(exact_log2(size)))); gen_write_ref_array_post_barrier(d, count, rscratch1); } __ leave(); + __ mov(r0, zr); // return 0 __ ret(lr); #ifdef BUILTIN_SIM { @@ -1140,11 +1143,16 @@ class StubGenerator: public StubCodeGenerator { StubCodeMark mark(this, "StubRoutines", name); address start = __ pc(); + __ enter(); + if (entry != NULL) { + *entry = __ pc(); + // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) + BLOCK_COMMENT("Entry:"); + } __ cmp(d, s); __ br(Assembler::LS, nooverlap_target); - __ enter(); if (is_oop) { __ push(RegSet::of(d, count), sp); // no registers are destroyed by this call @@ -1160,6 +1168,7 @@ class StubGenerator: public StubCodeGenerator { gen_write_ref_array_post_barrier(d, count, rscratch1); } __ leave(); + __ mov(r0, zr); // return 0 __ ret(lr); #ifdef BUILTIN_SIM { @@ -1559,7 +1568,29 @@ class StubGenerator: public StubCodeGenerator { Register dst_pos, // destination position (c_rarg3) Register length, Register temp, - Label& L_failed) { Unimplemented(); } + Label& L_failed) { + BLOCK_COMMENT("arraycopy_range_checks:"); + + assert_different_registers(rscratch1, temp); + + // if (src_pos + length > arrayOop(src)->length()) FAIL; + __ ldrw(rscratch1, Address(src, arrayOopDesc::length_offset_in_bytes())); + __ addw(temp, length, src_pos); + __ cmpw(temp, rscratch1); + __ br(Assembler::HI, L_failed); + + // if (dst_pos + length > arrayOop(dst)->length()) FAIL; + __ ldrw(rscratch1, Address(dst, arrayOopDesc::length_offset_in_bytes())); + __ addw(temp, length, dst_pos); + __ cmpw(temp, rscratch1); + __ br(Assembler::HI, L_failed); + + // Have to clean up high 32 bits of 'src_pos' and 'dst_pos'. + __ movw(src_pos, src_pos); + __ movw(dst_pos, dst_pos); + + BLOCK_COMMENT("arraycopy_range_checks done"); + } // These stubs get called from some dumb test routine. // I'll write them properly when they're called from @@ -1569,6 +1600,309 @@ class StubGenerator: public StubCodeGenerator { } + // + // Generate 'unsafe' array copy stub + // Though just as safe as the other stubs, it takes an unscaled + // size_t argument instead of an element count. + // + // Input: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - byte count, treated as ssize_t, can be zero + // + // Examines the alignment of the operands and dispatches + // to a long, int, short, or byte copy loop. + // + address generate_unsafe_copy(const char *name, + address byte_copy_entry) { +#ifdef PRODUCT + return StubRoutines::_jbyte_arraycopy; +#else + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ pc(); + __ enter(); // required for proper stackwalking of RuntimeStub frame + // bump this on entry, not on exit: + __ lea(rscratch2, ExternalAddress((address)&SharedRuntime::_unsafe_array_copy_ctr)); + __ incrementw(Address(rscratch2)); + __ b(RuntimeAddress(byte_copy_entry)); + return start; +#endif + } + + // + // Generate generic array copy stubs + // + // Input: + // c_rarg0 - src oop + // c_rarg1 - src_pos (32-bits) + // c_rarg2 - dst oop + // c_rarg3 - dst_pos (32-bits) + // c_rarg4 - element count (32-bits) + // + // Output: + // r0 == 0 - success + // r0 == -1^K - failure, where K is partial transfer count + // + address generate_generic_copy(const char *name, + address byte_copy_entry, address short_copy_entry, + address int_copy_entry, address oop_copy_entry, + address long_copy_entry, address checkcast_copy_entry) { + + Label L_failed, L_failed_0, L_objArray; + Label L_copy_bytes, L_copy_shorts, L_copy_ints, L_copy_longs; + + // Input registers + const Register src = c_rarg0; // source array oop + const Register src_pos = c_rarg1; // source position + const Register dst = c_rarg2; // destination array oop + const Register dst_pos = c_rarg3; // destination position + const Register length = c_rarg4; + + StubCodeMark mark(this, "StubRoutines", name); + + __ align(CodeEntryAlignment); + address start = __ pc(); + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + // bump this on entry, not on exit: + inc_counter_np(SharedRuntime::_generic_array_copy_ctr); + + //----------------------------------------------------------------------- + // Assembler stub will be used for this call to arraycopy + // if the following conditions are met: + // + // (1) src and dst must not be null. + // (2) src_pos must not be negative. + // (3) dst_pos must not be negative. + // (4) length must not be negative. + // (5) src klass and dst klass should be the same and not NULL. + // (6) src and dst should be arrays. + // (7) src_pos + length must not exceed length of src. + // (8) dst_pos + length must not exceed length of dst. + // + + // if (src == NULL) return -1; + __ cbz(src, L_failed); + + // if (src_pos < 0) return -1; + __ tbnz(src_pos, 31, L_failed); // i.e. sign bit set + + // if (dst == NULL) return -1; + __ cbz(dst, L_failed); + + // if (dst_pos < 0) return -1; + __ tbnz(dst_pos, 31, L_failed); // i.e. sign bit set + + // registers used as temp + const Register scratch_length = r16; // elements count to copy + const Register scratch_src_klass = r17; // array klass + const Register lh = r18; // layout helper + + // if (length < 0) return -1; + __ movw(scratch_length, length); // length (elements count, 32-bits value) + __ tbnz(scratch_length, 31, L_failed); // i.e. sign bit set + + __ load_klass(scratch_src_klass, src); +#ifdef ASSERT + // assert(src->klass() != NULL); + { + BLOCK_COMMENT("assert klasses not null {"); + Label L1, L2; + __ cbnz(scratch_src_klass, L2); // it is broken if klass is NULL + __ bind(L1); + __ stop("broken null klass"); + __ bind(L2); + __ load_klass(rscratch1, dst); + __ cbz(rscratch1, L1); // this would be broken also + BLOCK_COMMENT("} assert klasses not null done"); + } +#endif + + // Load layout helper (32-bits) + // + // |array_tag| | header_size | element_type | |log2_element_size| + // 32 30 24 16 8 2 0 + // + // array_tag: typeArray = 0x3, objArray = 0x2, non-array = 0x0 + // + + const int lh_offset = in_bytes(Klass::layout_helper_offset()); + + // Handle objArrays completely differently... + const jint objArray_lh = Klass::array_layout_helper(T_OBJECT); + __ ldrw(lh, Address(scratch_src_klass, lh_offset)); + __ movw(rscratch1, objArray_lh); + __ eorw(rscratch2, lh, rscratch1); + __ cbzw(rscratch2, L_objArray); + + // if (src->klass() != dst->klass()) return -1; + __ load_klass(rscratch2, dst); + __ eor(rscratch2, rscratch2, scratch_src_klass); + __ cbnz(rscratch2, L_failed); + + // if (!src->is_Array()) return -1; + __ tbz(lh, 31, L_failed); // i.e. (lh >= 0) + + // At this point, it is known to be a typeArray (array_tag 0x3). +#ifdef ASSERT + { + BLOCK_COMMENT("assert primitive array {"); + Label L; + __ movw(rscratch2, Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift); + __ cmpw(lh, rscratch2); + __ br(Assembler::GE, L); + __ stop("must be a primitive array"); + __ bind(L); + BLOCK_COMMENT("} assert primitive array done"); + } +#endif + + arraycopy_range_checks(src, src_pos, dst, dst_pos, scratch_length, + rscratch2, L_failed); + + // TypeArrayKlass + // + // src_addr = (src + array_header_in_bytes()) + (src_pos << log2elemsize); + // dst_addr = (dst + array_header_in_bytes()) + (dst_pos << log2elemsize); + // + + const Register rscratch1_offset = rscratch1; // array offset + const Register r18_elsize = lh; // element size + + __ ubfx(rscratch1_offset, lh, Klass::_lh_header_size_shift, + exact_log2(Klass::_lh_header_size_mask+1)); // array_offset + __ add(src, src, rscratch1_offset); // src array offset + __ add(dst, dst, rscratch1_offset); // dst array offset + BLOCK_COMMENT("choose copy loop based on element size"); + + // next registers should be set before the jump to corresponding stub + const Register from = c_rarg0; // source array address + const Register to = c_rarg1; // destination array address + const Register count = c_rarg2; // elements count + + // 'from', 'to', 'count' registers should be set in such order + // since they are the same as 'src', 'src_pos', 'dst'. + + assert(Klass::_lh_log2_element_size_shift == 0, "fix this code"); + + // The possible values of elsize are 0-3, i.e. exact_log2(element + // size in bytes). We do a simple bitwise binary search. + __ BIND(L_copy_bytes); + __ tbnz(r18_elsize, 1, L_copy_ints); + __ tbnz(r18_elsize, 0, L_copy_shorts); + __ lea(from, Address(src, src_pos));// src_addr + __ lea(to, Address(dst, dst_pos));// dst_addr + __ movw(count, scratch_length); // length + __ b(RuntimeAddress(byte_copy_entry)); + + __ BIND(L_copy_shorts); + __ lea(from, Address(src, src_pos, Address::lsl(1)));// src_addr + __ lea(to, Address(dst, dst_pos, Address::lsl(1)));// dst_addr + __ movw(count, scratch_length); // length + __ b(RuntimeAddress(short_copy_entry)); + + __ BIND(L_copy_ints); + __ tbnz(r18_elsize, 0, L_copy_longs); + __ lea(from, Address(src, src_pos, Address::lsl(2)));// src_addr + __ lea(to, Address(dst, dst_pos, Address::lsl(2)));// dst_addr + __ movw(count, scratch_length); // length + __ b(RuntimeAddress(int_copy_entry)); + + __ BIND(L_copy_longs); +#ifdef ASSERT + { + BLOCK_COMMENT("assert long copy {"); + Label L; + __ andw(lh, lh, Klass::_lh_log2_element_size_mask); // lh -> r18_elsize + __ cmpw(r18_elsize, LogBytesPerLong); + __ br(Assembler::EQ, L); + __ stop("must be long copy, but elsize is wrong"); + __ bind(L); + BLOCK_COMMENT("} assert long copy done"); + } +#endif + __ lea(from, Address(src, src_pos, Address::lsl(3)));// src_addr + __ lea(to, Address(dst, dst_pos, Address::lsl(3)));// dst_addr + __ movw(count, scratch_length); // length + __ b(RuntimeAddress(long_copy_entry)); + + // ObjArrayKlass + __ BIND(L_objArray); + // live at this point: scratch_src_klass, scratch_length, src[_pos], dst[_pos] + + Label L_plain_copy, L_checkcast_copy; + // test array classes for subtyping + __ load_klass(r18, dst); + __ cmp(scratch_src_klass, r18); // usual case is exact equality + __ br(Assembler::NE, L_checkcast_copy); + + // Identically typed arrays can be copied without element-wise checks. + arraycopy_range_checks(src, src_pos, dst, dst_pos, scratch_length, + rscratch2, L_failed); + + __ lea(from, Address(src, src_pos, Address::lsl(3))); + __ add(from, from, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ lea(to, Address(dst, dst_pos, Address::lsl(3))); + __ add(to, to, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ movw(count, scratch_length); // length + __ BIND(L_plain_copy); + __ b(RuntimeAddress(oop_copy_entry)); + + __ BIND(L_checkcast_copy); + // live at this point: scratch_src_klass, scratch_length, r18 (dst_klass) + { + // Before looking at dst.length, make sure dst is also an objArray. + __ ldrw(rscratch1, Address(r18, lh_offset)); + __ movw(rscratch2, objArray_lh); + __ eorw(rscratch1, rscratch1, rscratch2); + __ cbnzw(rscratch1, L_failed); + + // It is safe to examine both src.length and dst.length. + arraycopy_range_checks(src, src_pos, dst, dst_pos, scratch_length, + r18, L_failed); + + const Register rscratch2_dst_klass = rscratch2; + __ load_klass(rscratch2_dst_klass, dst); // reload + + // Marshal the base address arguments now, freeing registers. + __ lea(from, Address(src, src_pos, Address::lsl(3))); + __ add(from, from, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ lea(to, Address(dst, dst_pos, Address::lsl(3))); + __ add(to, to, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ movw(count, length); // length (reloaded) + Register sco_temp = c_rarg3; // this register is free now + assert_different_registers(from, to, count, sco_temp, + rscratch2_dst_klass, scratch_src_klass); + // assert_clean_int(count, sco_temp); + + // Generate the type check. + const int sco_offset = in_bytes(Klass::super_check_offset_offset()); + __ ldrw(sco_temp, Address(rscratch2_dst_klass, sco_offset)); + // assert_clean_int(sco_temp, r18); + generate_type_check(scratch_src_klass, sco_temp, rscratch2_dst_klass, L_plain_copy); + + // Fetch destination element klass from the ObjArrayKlass header. + int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); + __ ldr(rscratch2_dst_klass, Address(rscratch2_dst_klass, ek_offset)); + __ ldrw(sco_temp, Address(rscratch2_dst_klass, sco_offset)); + + // the checkcast_copy loop needs two extra arguments: + assert(c_rarg3 == sco_temp, "#3 already in place"); + // Set up arguments for checkcast_copy_entry. + __ mov(c_rarg4, rscratch2_dst_klass); // dst.klass.element_klass + __ b(RuntimeAddress(checkcast_copy_entry)); + } + + __ BIND(L_failed); + __ mov(r0, -1); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(lr); + + return start; + } + void generate_arraycopy_stubs() { address entry; address entry_jbyte_arraycopy; @@ -1655,6 +1989,18 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_checkcast_arraycopy = generate_checkcast_copy("checkcast_arraycopy", &entry_checkcast_arraycopy); StubRoutines::_checkcast_arraycopy_uninit = generate_checkcast_copy("checkcast_arraycopy_uninit", NULL, /*dest_uninitialized*/true); + + StubRoutines::_unsafe_arraycopy = generate_unsafe_copy("unsafe_arraycopy", + entry_jbyte_arraycopy); + + StubRoutines::_generic_arraycopy = generate_generic_copy("generic_arraycopy", + entry_jbyte_arraycopy, + entry_jshort_arraycopy, + entry_jint_arraycopy, + entry_oop_arraycopy, + entry_jlong_arraycopy, + entry_checkcast_arraycopy); + } void generate_math_stubs() { Unimplemented(); } @@ -1973,7 +2319,7 @@ class StubGenerator: public StubCodeGenerator { // c_rarg4 - input length // // Output: - // rax - input length + // r0 - input length // address generate_cipherBlockChaining_decryptAESCrypt() { assert(UseAES, "need AES instructions and misaligned SSE support"); From c095394bced5c3a8155c651fa28df81709815a28 Mon Sep 17 00:00:00 2001 From: Ed Nevill Date: Tue, 8 Dec 2015 14:26:17 +0000 Subject: [PATCH 052/215] 8144498: aarch64: large code cache generates SEGV Fix pd_call_destination to use is_call_at rather than is_call Reviewed-by: aph, adinn --- hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp index 3ab4f0b7b2c..42d2977b1b5 100644 --- a/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/relocInfo_aarch64.cpp @@ -59,7 +59,7 @@ void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { address Relocation::pd_call_destination(address orig_addr) { assert(is_call(), "should be a call here"); - if (is_call()) { + if (NativeCall::is_call_at(addr())) { address trampoline = nativeCall_at(addr())->get_trampoline(); if (trampoline) { return nativeCallTrampolineStub_at(trampoline)->destination(); From 7c018b1a000ff5f480b7c5acfd2770a23bb6e583 Mon Sep 17 00:00:00 2001 From: Ambarish Rapte Date: Wed, 9 Dec 2015 02:41:51 +0400 Subject: [PATCH 053/215] 8060137: Removing Text from TextField / TextArea is not possible after typing Reviewed-by: ssadetsky, psadhukhan --- .../share/classes/java/awt/TextComponent.java | 22 ++-- .../TextAreaEditing/TextAreaEditing.java | 28 ++++- .../TextFieldEditing/TextFieldEditing.java | 113 ++++++++++++++++++ 3 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 jdk/test/java/awt/TextField/TextFieldEditing/TextFieldEditing.java diff --git a/jdk/src/java.desktop/share/classes/java/awt/TextComponent.java b/jdk/src/java.desktop/share/classes/java/awt/TextComponent.java index 9e7c22a49bb..191412a30b7 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/TextComponent.java +++ b/jdk/src/java.desktop/share/classes/java/awt/TextComponent.java @@ -229,15 +229,21 @@ public class TextComponent extends Component implements Accessible { * @see java.awt.TextComponent#getText */ public synchronized void setText(String t) { - boolean skipTextEvent = (text == null || text.isEmpty()) - && (t == null || t.isEmpty()); - text = (t != null) ? t : ""; + if (t == null) { + t = ""; + } TextComponentPeer peer = (TextComponentPeer)this.peer; - // Please note that we do not want to post an event - // if TextArea.setText() or TextField.setText() replaces an empty text - // by an empty text, that is, if component's text remains unchanged. - if (peer != null && !skipTextEvent) { - peer.setText(text); + if (peer != null) { + text = peer.getText(); + // Please note that we do not want to post an event + // if TextArea.setText() or TextField.setText() replaces text + // by same text, that is, if component's text remains unchanged. + if (!t.equals(text)) { + text = t; + peer.setText(text); + } + } else { + text = t; } } diff --git a/jdk/test/java/awt/TextArea/TextAreaEditing/TextAreaEditing.java b/jdk/test/java/awt/TextArea/TextAreaEditing/TextAreaEditing.java index f3306784ef8..6b7dcfaf2c0 100644 --- a/jdk/test/java/awt/TextArea/TextAreaEditing/TextAreaEditing.java +++ b/jdk/test/java/awt/TextArea/TextAreaEditing/TextAreaEditing.java @@ -23,16 +23,23 @@ /* @test - @bug 8040322 + @bug 8040322 8060137 + @library ../../regtesthelpers + @build Util @summary Test TextArea APIs replaceRange, insert, append & setText @run main TextAreaEditing */ import java.awt.Frame; +import java.awt.Robot; import java.awt.TextArea; +import java.awt.AWTException; +import java.awt.event.KeyEvent; +import test.java.awt.regtesthelpers.Util; public class TextAreaEditing { + final static Robot robot = Util.createRobot(); private int testFailCount; private boolean isTestFail; private StringBuilder testFailMessage; @@ -61,6 +68,7 @@ public class TextAreaEditing { textArea.testReplaceRange(); textArea.testInsert(); textArea.testAppend(); + textArea.testSetText(); textArea.checkFailures(); textArea.dispose(); } @@ -119,6 +127,24 @@ public class TextAreaEditing { checkTest(""); } + private void testSetText() { + textArea.setText(null); + textArea.requestFocus(); + Util.clickOnComp(textArea, robot); + Util.waitForIdle(robot); + robot.keyPress(KeyEvent.VK_A); + robot.delay(5); + robot.keyRelease(KeyEvent.VK_A); + Util.waitForIdle(robot); + textArea.setText(null); + checkTest(""); + textArea.setText("CaseSensitive"); + checkTest("CaseSensitive"); + textArea.setText("caseSensitive"); + checkTest("caseSensitive"); + + } + private void checkTest(String str) { if (str != null && !str.equals(textArea.getText())) { testFailMessage.append("TestFail line : "); diff --git a/jdk/test/java/awt/TextField/TextFieldEditing/TextFieldEditing.java b/jdk/test/java/awt/TextField/TextFieldEditing/TextFieldEditing.java new file mode 100644 index 00000000000..503b6e35129 --- /dev/null +++ b/jdk/test/java/awt/TextField/TextFieldEditing/TextFieldEditing.java @@ -0,0 +1,113 @@ +/* + * 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 8060137 + @library ../../regtesthelpers + @build Util + @summary Test TextField setText API + @run main TextFieldEditing + */ + +import java.awt.Frame; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.AWTException; +import java.awt.event.KeyEvent; +import test.java.awt.regtesthelpers.Util; + +public class TextFieldEditing { + + final static Robot robot = Util.createRobot(); + private int testFailCount; + private boolean isTestFail; + private StringBuilder testFailMessage; + + private Frame mainFrame; + private TextField textField; + + private TextFieldEditing() { + testFailMessage = new StringBuilder(); + mainFrame = new Frame(); + mainFrame.setSize(200, 200); + + textField = new TextField(); + mainFrame.add(textField); + mainFrame.setVisible(true); + } + + private void dispose() { + if (mainFrame != null) { + mainFrame.dispose(); + } + } + + public static void main(String[] s) { + TextFieldEditing textField = new TextFieldEditing(); + textField.testSetText(); + textField.checkFailures(); + textField.dispose(); + } + + private void testSetText() { + textField.setText(null); + textField.requestFocus(); + Util.clickOnComp(textField, robot); + Util.waitForIdle(robot); + robot.keyPress(KeyEvent.VK_A); + robot.delay(5); + robot.keyRelease(KeyEvent.VK_A); + Util.waitForIdle(robot); + textField.setText(null); + checkTest(""); + textField.setText("CaseSensitive"); + checkTest("CaseSensitive"); + textField.setText("caseSensitive"); + checkTest("caseSensitive"); + } + + private void checkTest(String str) { + if (str != null && !str.equals(textField.getText())) { + testFailMessage.append("TestFail line : "); + testFailMessage.append(Thread.currentThread().getStackTrace()[2]. + getLineNumber()); + testFailMessage.append(" TextField string : \""); + testFailMessage.append(textField.getText()); + testFailMessage.append("\" does not match expected string : \""); + testFailMessage.append(str).append("\""); + testFailMessage.append(System.getProperty("line.separator")); + testFailCount++; + isTestFail = true; + } + } + + private void checkFailures() { + if (isTestFail) { + testFailMessage.insert(0, "Test Fail count : " + testFailCount + + System.getProperty("line.separator")); + dispose(); + throw new RuntimeException(testFailMessage.toString()); + } + } +} From 18ace0f732d8acfd7bfaf8f18a50549d8822bf20 Mon Sep 17 00:00:00 2001 From: Manajit Halder Date: Tue, 8 Dec 2015 19:50:14 +0300 Subject: [PATCH 054/215] 7159591: [macosx] In SetFontTest there's no space for the second button Reviewed-by: arapte, serb --- jdk/test/java/awt/List/SetFontTest/SetFontTest.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/test/java/awt/List/SetFontTest/SetFontTest.html b/jdk/test/java/awt/List/SetFontTest/SetFontTest.html index db33b8c83a8..3ac0d99fc51 100644 --- a/jdk/test/java/awt/List/SetFontTest/SetFontTest.html +++ b/jdk/test/java/awt/List/SetFontTest/SetFontTest.html @@ -38,6 +38,6 @@

See the dialog box (usually in upper left corner) for instructions

- + From bf5db7225437e03f0c0ec4e74468ea9538e32992 Mon Sep 17 00:00:00 2001 From: Christian Thalinger Date: Mon, 14 Dec 2015 17:02:02 -1000 Subject: [PATCH 055/215] 8134994: use separate VMStructs databases for SA and JVMCI Reviewed-by: kbarrett --- hotspot/src/cpu/x86/vm/vm_version_x86.hpp | 1 + .../hotspot/HotSpotResolvedJavaFieldImpl.java | 2 +- .../HotSpotResolvedObjectTypeImpl.java | 3 +- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 322 +++---- .../ci/hotspotvmconfig/HotSpotVMManual.java | 44 - .../src/share/vm/classfile/javaClasses.hpp | 1 + hotspot/src/share/vm/classfile/vmSymbols.hpp | 1 + hotspot/src/share/vm/code/codeBlob.hpp | 2 + hotspot/src/share/vm/code/codeCache.hpp | 1 + hotspot/src/share/vm/code/nmethod.hpp | 1 + hotspot/src/share/vm/compiler/compileTask.hpp | 1 + hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp | 21 - .../src/share/vm/gc/shared/collectedHeap.hpp | 1 + .../vm/gc/shared/threadLocalAllocBuffer.hpp | 1 + .../src/share/vm/jvmci/jvmciCodeInstaller.hpp | 2 +- .../src/share/vm/jvmci/jvmciCompilerToVM.cpp | 203 +++-- .../src/share/vm/jvmci/jvmciCompilerToVM.hpp | 57 +- hotspot/src/share/vm/jvmci/jvmciEnv.hpp | 1 + hotspot/src/share/vm/jvmci/jvmciRuntime.cpp | 4 - .../src/share/vm/jvmci/vmStructs_jvmci.cpp | 849 ++++++++++++++++++ .../src/share/vm/jvmci/vmStructs_jvmci.hpp | 131 +-- hotspot/src/share/vm/oops/constMethod.hpp | 2 +- hotspot/src/share/vm/oops/constantPool.hpp | 1 + hotspot/src/share/vm/oops/instanceKlass.hpp | 1 + hotspot/src/share/vm/oops/klass.hpp | 1 + hotspot/src/share/vm/oops/klassVtable.hpp | 1 + hotspot/src/share/vm/oops/method.hpp | 1 + hotspot/src/share/vm/oops/methodCounters.hpp | 1 + hotspot/src/share/vm/oops/methodData.hpp | 9 + hotspot/src/share/vm/oops/objArrayKlass.hpp | 1 + hotspot/src/share/vm/oops/oop.hpp | 1 + hotspot/src/share/vm/runtime/basicLock.hpp | 1 + .../src/share/vm/runtime/deoptimization.hpp | 1 + .../src/share/vm/runtime/javaFrameAnchor.hpp | 1 + hotspot/src/share/vm/runtime/os.hpp | 1 + hotspot/src/share/vm/runtime/osThread.hpp | 1 + hotspot/src/share/vm/runtime/thread.hpp | 2 + hotspot/src/share/vm/runtime/vmStructs.cpp | 218 +---- hotspot/src/share/vm/runtime/vmStructs.hpp | 147 +++ hotspot/src/share/vm/utilities/array.hpp | 1 + hotspot/src/share/vm/utilities/exceptions.hpp | 1 + 41 files changed, 1367 insertions(+), 675 deletions(-) delete mode 100644 hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMManual.java create mode 100644 hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp diff --git a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp index 784e8475da9..624f138d5be 100644 --- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp +++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp @@ -30,6 +30,7 @@ class VM_Version : public Abstract_VM_Version { friend class VMStructs; + friend class JVMCIVMStructs; public: // cpuid result register layouts. These are all unions of a uint32_t // (in case anyone wants access to the register as a whole) and a bitfield. diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java index cd89be3e563..d565dfe4d39 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java @@ -190,7 +190,7 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField, HotSpotP @Override public boolean isSynthetic() { - return (config().syntheticFlag & modifiers) != 0; + return (config().jvmAccSynthetic & modifiers) != 0; } /** diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 4ef227ec823..65d92b1d8fd 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -324,8 +324,7 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem @Override public boolean hasFinalizer() { - HotSpotVMConfig config = config(); - return (getAccessFlags() & config.klassHasFinalizerFlag) != 0; + return (getAccessFlags() & config().jvmAccHasFinalizer) != 0; } @Override 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 2709c0807ac..228bff3a9a7 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 @@ -37,7 +37,6 @@ import jdk.vm.ci.hotspotvmconfig.HotSpotVMConstant; import jdk.vm.ci.hotspotvmconfig.HotSpotVMData; import jdk.vm.ci.hotspotvmconfig.HotSpotVMField; import jdk.vm.ci.hotspotvmconfig.HotSpotVMFlag; -import jdk.vm.ci.hotspotvmconfig.HotSpotVMManual; import jdk.vm.ci.hotspotvmconfig.HotSpotVMType; import sun.misc.Unsafe; @@ -68,11 +67,11 @@ public class HotSpotVMConfig { assert gHotSpotVMData != 0; // Make FindBugs happy. - gHotSpotVMStructs = 0; - gHotSpotVMTypes = 0; - gHotSpotVMIntConstants = 0; - gHotSpotVMLongConstants = 0; - gHotSpotVMAddresses = 0; + jvmciHotSpotVMStructs = 0; + jvmciHotSpotVMTypes = 0; + jvmciHotSpotVMIntConstants = 0; + jvmciHotSpotVMLongConstants = 0; + jvmciHotSpotVMAddresses = 0; // Initialize the gHotSpotVM fields. for (Field f : HotSpotVMConfig.class.getDeclaredFields()) { @@ -89,41 +88,17 @@ public class HotSpotVMConfig { } // Quick sanity check. - assert gHotSpotVMStructs != 0; - assert gHotSpotVMTypes != 0; - assert gHotSpotVMIntConstants != 0; - assert gHotSpotVMLongConstants != 0; - assert gHotSpotVMAddresses != 0; + assert jvmciHotSpotVMStructs != 0; + assert jvmciHotSpotVMTypes != 0; + assert jvmciHotSpotVMIntConstants != 0; + assert jvmciHotSpotVMLongConstants != 0; + assert jvmciHotSpotVMAddresses != 0; initialize(); oopEncoding = new CompressEncoding(narrowOopBase, narrowOopShift, logMinObjAlignment()); klassEncoding = new CompressEncoding(narrowKlassBase, narrowKlassShift, logKlassAlignment); - final long barrierSetAddress = UNSAFE.getAddress(universeCollectedHeap + collectedHeapBarrierSetOffset); - final int kind = UNSAFE.getInt(barrierSetAddress + barrierSetFakeRttiOffset + fakeRttiConcreteTagOffset); - if ((kind == barrierSetCardTableModRef) || (kind == barrierSetCardTableForRS) || (kind == barrierSetCardTableExtension) || (kind == barrierSetG1SATBCT) || (kind == barrierSetG1SATBCTLogging)) { - final long base = UNSAFE.getAddress(barrierSetAddress + cardTableModRefBSByteMapBaseOffset); - assert base != 0 : "unexpected byte_map_base: " + base; - cardtableStartAddress = base; - cardtableShift = cardTableModRefBSCardShift; - } else if (kind == barrierSetModRef) { - // No post barriers - cardtableStartAddress = 0; - cardtableShift = 0; - } else { - cardtableStartAddress = -1; - cardtableShift = -1; - } - - // Now handle all HotSpotVMManual fields. - inlineCacheMissStub = inlineCacheMissBlob + UNSAFE.getInt(inlineCacheMissBlob + codeBlobCodeOffsetOffset); - handleWrongMethodStub = wrongMethodBlob + UNSAFE.getInt(wrongMethodBlob + codeBlobCodeOffsetOffset); - handleDeoptStub = deoptBlob + UNSAFE.getInt(deoptBlob + codeBlobCodeOffsetOffset) + UNSAFE.getInt(deoptBlob + deoptimizationBlobUnpackOffsetOffset); - uncommonTrapStub = deoptBlob + UNSAFE.getInt(deoptBlob + codeBlobCodeOffsetOffset) + UNSAFE.getInt(deoptBlob + deoptimizationBlobUncommonTrapOffsetOffset); - - tlabAlignmentReserve = roundUp(threadLocalAllocBufferEndReserve(), minObjAlignment()); - assert check(); assert HotSpotVMConfigVerifier.check(); } @@ -139,28 +114,28 @@ public class HotSpotVMConfig { private void initialize() { // Fill the VM fields hash map. HashMap vmFields = new HashMap<>(); - for (VMFields.Field e : new VMFields(gHotSpotVMStructs)) { + for (VMFields.Field e : new VMFields(jvmciHotSpotVMStructs)) { vmFields.put(e.getName(), e); } // Fill the VM types hash map. HashMap vmTypes = new HashMap<>(); - for (VMTypes.Type e : new VMTypes(gHotSpotVMTypes)) { + for (VMTypes.Type e : new VMTypes(jvmciHotSpotVMTypes)) { vmTypes.put(e.getTypeName(), e); } // Fill the VM constants hash map. HashMap vmConstants = new HashMap<>(); - for (AbstractConstant e : new VMIntConstants(gHotSpotVMIntConstants)) { + for (AbstractConstant e : new VMIntConstants(jvmciHotSpotVMIntConstants)) { vmConstants.put(e.getName(), e); } - for (AbstractConstant e : new VMAddresses(gHotSpotVMLongConstants)) { + for (AbstractConstant e : new VMLongConstants(jvmciHotSpotVMLongConstants)) { vmConstants.put(e.getName(), e); } // Fill the VM addresses hash map. HashMap vmAddresses = new HashMap<>(); - for (VMAddresses.Address e : new VMAddresses(gHotSpotVMAddresses)) { + for (VMAddresses.Address e : new VMAddresses(jvmciHotSpotVMAddresses)) { vmAddresses.put(e.getName(), e); } @@ -213,6 +188,7 @@ public class HotSpotVMConfig { if (entry == null) { throw new JVMCIError(f.getName() + ": expected VM type not found: " + name); } + switch (annotation.get()) { case SIZE: setField(f, entry.getSize()); @@ -371,14 +347,14 @@ public class HotSpotVMConfig { /** * VMStructEntry (see {@code vmStructs.hpp}). */ - @HotSpotVMData(index = 0) @Stable private long gHotSpotVMStructs; - @HotSpotVMData(index = 1) @Stable private long gHotSpotVMStructEntryTypeNameOffset; - @HotSpotVMData(index = 2) @Stable private long gHotSpotVMStructEntryFieldNameOffset; - @HotSpotVMData(index = 3) @Stable private long gHotSpotVMStructEntryTypeStringOffset; - @HotSpotVMData(index = 4) @Stable private long gHotSpotVMStructEntryIsStaticOffset; - @HotSpotVMData(index = 5) @Stable private long gHotSpotVMStructEntryOffsetOffset; - @HotSpotVMData(index = 6) @Stable private long gHotSpotVMStructEntryAddressOffset; - @HotSpotVMData(index = 7) @Stable private long gHotSpotVMStructEntryArrayStride; + @HotSpotVMData(index = 0) @Stable private long jvmciHotSpotVMStructs; + @HotSpotVMData(index = 1) @Stable private long jvmciHotSpotVMStructEntryTypeNameOffset; + @HotSpotVMData(index = 2) @Stable private long jvmciHotSpotVMStructEntryFieldNameOffset; + @HotSpotVMData(index = 3) @Stable private long jvmciHotSpotVMStructEntryTypeStringOffset; + @HotSpotVMData(index = 4) @Stable private long jvmciHotSpotVMStructEntryIsStaticOffset; + @HotSpotVMData(index = 5) @Stable private long jvmciHotSpotVMStructEntryOffsetOffset; + @HotSpotVMData(index = 6) @Stable private long jvmciHotSpotVMStructEntryAddressOffset; + @HotSpotVMData(index = 7) @Stable private long jvmciHotSpotVMStructEntryArrayStride; final class VMFields implements Iterable { @@ -394,7 +370,7 @@ public class HotSpotVMConfig { private int index = 0; private Field current() { - return new Field(address + gHotSpotVMStructEntryArrayStride * index); + return new Field(address + jvmciHotSpotVMStructEntryArrayStride * index); } /** @@ -422,30 +398,30 @@ public class HotSpotVMConfig { } public String getTypeName() { - long typeNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryTypeNameOffset); + long typeNameAddress = UNSAFE.getAddress(entryAddress + jvmciHotSpotVMStructEntryTypeNameOffset); return readCString(UNSAFE, typeNameAddress); } public String getFieldName() { - long fieldNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryFieldNameOffset); + long fieldNameAddress = UNSAFE.getAddress(entryAddress + jvmciHotSpotVMStructEntryFieldNameOffset); return readCString(UNSAFE, fieldNameAddress); } public String getTypeString() { - long typeStringAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryTypeStringOffset); + long typeStringAddress = UNSAFE.getAddress(entryAddress + jvmciHotSpotVMStructEntryTypeStringOffset); return readCString(UNSAFE, typeStringAddress); } public boolean isStatic() { - return UNSAFE.getInt(entryAddress + gHotSpotVMStructEntryIsStaticOffset) != 0; + return UNSAFE.getInt(entryAddress + jvmciHotSpotVMStructEntryIsStaticOffset) != 0; } public long getOffset() { - return UNSAFE.getLong(entryAddress + gHotSpotVMStructEntryOffsetOffset); + return UNSAFE.getLong(entryAddress + jvmciHotSpotVMStructEntryOffsetOffset); } public long getAddress() { - return UNSAFE.getAddress(entryAddress + gHotSpotVMStructEntryAddressOffset); + return UNSAFE.getAddress(entryAddress + jvmciHotSpotVMStructEntryAddressOffset); } public String getName() { @@ -466,6 +442,7 @@ public class HotSpotVMConfig { case "address": case "intptr_t": case "uintptr_t": + case "size_t": return UNSAFE.getAddress(getAddress()); default: // All foo* types are addresses. @@ -487,14 +464,14 @@ public class HotSpotVMConfig { /** * VMTypeEntry (see vmStructs.hpp). */ - @HotSpotVMData(index = 8) @Stable private long gHotSpotVMTypes; - @HotSpotVMData(index = 9) @Stable private long gHotSpotVMTypeEntryTypeNameOffset; - @HotSpotVMData(index = 10) @Stable private long gHotSpotVMTypeEntrySuperclassNameOffset; - @HotSpotVMData(index = 11) @Stable private long gHotSpotVMTypeEntryIsOopTypeOffset; - @HotSpotVMData(index = 12) @Stable private long gHotSpotVMTypeEntryIsIntegerTypeOffset; - @HotSpotVMData(index = 13) @Stable private long gHotSpotVMTypeEntryIsUnsignedOffset; - @HotSpotVMData(index = 14) @Stable private long gHotSpotVMTypeEntrySizeOffset; - @HotSpotVMData(index = 15) @Stable private long gHotSpotVMTypeEntryArrayStride; + @HotSpotVMData(index = 8) @Stable private long jvmciHotSpotVMTypes; + @HotSpotVMData(index = 9) @Stable private long jvmciHotSpotVMTypeEntryTypeNameOffset; + @HotSpotVMData(index = 10) @Stable private long jvmciHotSpotVMTypeEntrySuperclassNameOffset; + @HotSpotVMData(index = 11) @Stable private long jvmciHotSpotVMTypeEntryIsOopTypeOffset; + @HotSpotVMData(index = 12) @Stable private long jvmciHotSpotVMTypeEntryIsIntegerTypeOffset; + @HotSpotVMData(index = 13) @Stable private long jvmciHotSpotVMTypeEntryIsUnsignedOffset; + @HotSpotVMData(index = 14) @Stable private long jvmciHotSpotVMTypeEntrySizeOffset; + @HotSpotVMData(index = 15) @Stable private long jvmciHotSpotVMTypeEntryArrayStride; final class VMTypes implements Iterable { @@ -510,7 +487,7 @@ public class HotSpotVMConfig { private int index = 0; private Type current() { - return new Type(address + gHotSpotVMTypeEntryArrayStride * index); + return new Type(address + jvmciHotSpotVMTypeEntryArrayStride * index); } /** @@ -538,29 +515,29 @@ public class HotSpotVMConfig { } public String getTypeName() { - long typeNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMTypeEntryTypeNameOffset); + long typeNameAddress = UNSAFE.getAddress(entryAddress + jvmciHotSpotVMTypeEntryTypeNameOffset); return readCString(UNSAFE, typeNameAddress); } public String getSuperclassName() { - long superclassNameAddress = UNSAFE.getAddress(entryAddress + gHotSpotVMTypeEntrySuperclassNameOffset); + long superclassNameAddress = UNSAFE.getAddress(entryAddress + jvmciHotSpotVMTypeEntrySuperclassNameOffset); return readCString(UNSAFE, superclassNameAddress); } public boolean isOopType() { - return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsOopTypeOffset) != 0; + return UNSAFE.getInt(entryAddress + jvmciHotSpotVMTypeEntryIsOopTypeOffset) != 0; } public boolean isIntegerType() { - return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsIntegerTypeOffset) != 0; + return UNSAFE.getInt(entryAddress + jvmciHotSpotVMTypeEntryIsIntegerTypeOffset) != 0; } public boolean isUnsigned() { - return UNSAFE.getInt(entryAddress + gHotSpotVMTypeEntryIsUnsignedOffset) != 0; + return UNSAFE.getInt(entryAddress + jvmciHotSpotVMTypeEntryIsUnsignedOffset) != 0; } public long getSize() { - return UNSAFE.getLong(entryAddress + gHotSpotVMTypeEntrySizeOffset); + return UNSAFE.getLong(entryAddress + jvmciHotSpotVMTypeEntrySizeOffset); } @Override @@ -594,10 +571,10 @@ public class HotSpotVMConfig { /** * VMIntConstantEntry (see vmStructs.hpp). */ - @HotSpotVMData(index = 16) @Stable private long gHotSpotVMIntConstants; - @HotSpotVMData(index = 17) @Stable private long gHotSpotVMIntConstantEntryNameOffset; - @HotSpotVMData(index = 18) @Stable private long gHotSpotVMIntConstantEntryValueOffset; - @HotSpotVMData(index = 19) @Stable private long gHotSpotVMIntConstantEntryArrayStride; + @HotSpotVMData(index = 16) @Stable private long jvmciHotSpotVMIntConstants; + @HotSpotVMData(index = 17) @Stable private long jvmciHotSpotVMIntConstantEntryNameOffset; + @HotSpotVMData(index = 18) @Stable private long jvmciHotSpotVMIntConstantEntryValueOffset; + @HotSpotVMData(index = 19) @Stable private long jvmciHotSpotVMIntConstantEntryArrayStride; final class VMIntConstants implements Iterable { @@ -613,7 +590,7 @@ public class HotSpotVMConfig { private int index = 0; private Constant current() { - return new Constant(address + gHotSpotVMIntConstantEntryArrayStride * index); + return new Constant(address + jvmciHotSpotVMIntConstantEntryArrayStride * index); } /** @@ -635,7 +612,7 @@ public class HotSpotVMConfig { final class Constant extends AbstractConstant { Constant(long address) { - super(address, gHotSpotVMIntConstantEntryNameOffset, gHotSpotVMIntConstantEntryValueOffset); + super(address, jvmciHotSpotVMIntConstantEntryNameOffset, jvmciHotSpotVMIntConstantEntryValueOffset); } @Override @@ -653,10 +630,10 @@ public class HotSpotVMConfig { /** * VMLongConstantEntry (see vmStructs.hpp). */ - @HotSpotVMData(index = 20) @Stable private long gHotSpotVMLongConstants; - @HotSpotVMData(index = 21) @Stable private long gHotSpotVMLongConstantEntryNameOffset; - @HotSpotVMData(index = 22) @Stable private long gHotSpotVMLongConstantEntryValueOffset; - @HotSpotVMData(index = 23) @Stable private long gHotSpotVMLongConstantEntryArrayStride; + @HotSpotVMData(index = 20) @Stable private long jvmciHotSpotVMLongConstants; + @HotSpotVMData(index = 21) @Stable private long jvmciHotSpotVMLongConstantEntryNameOffset; + @HotSpotVMData(index = 22) @Stable private long jvmciHotSpotVMLongConstantEntryValueOffset; + @HotSpotVMData(index = 23) @Stable private long jvmciHotSpotVMLongConstantEntryArrayStride; final class VMLongConstants implements Iterable { @@ -672,7 +649,7 @@ public class HotSpotVMConfig { private int index = 0; private Constant currentEntry() { - return new Constant(address + gHotSpotVMLongConstantEntryArrayStride * index); + return new Constant(address + jvmciHotSpotVMLongConstantEntryArrayStride * index); } /** @@ -694,7 +671,7 @@ public class HotSpotVMConfig { final class Constant extends AbstractConstant { Constant(long address) { - super(address, gHotSpotVMLongConstantEntryNameOffset, gHotSpotVMLongConstantEntryValueOffset); + super(address, jvmciHotSpotVMLongConstantEntryNameOffset, jvmciHotSpotVMLongConstantEntryValueOffset); } @Override @@ -712,10 +689,10 @@ public class HotSpotVMConfig { /** * VMAddressEntry (see vmStructs.hpp). */ - @HotSpotVMData(index = 24) @Stable private long gHotSpotVMAddresses; - @HotSpotVMData(index = 25) @Stable private long gHotSpotVMAddressEntryNameOffset; - @HotSpotVMData(index = 26) @Stable private long gHotSpotVMAddressEntryValueOffset; - @HotSpotVMData(index = 27) @Stable private long gHotSpotVMAddressEntryArrayStride; + @HotSpotVMData(index = 24) @Stable private long jvmciHotSpotVMAddresses; + @HotSpotVMData(index = 25) @Stable private long jvmciHotSpotVMAddressEntryNameOffset; + @HotSpotVMData(index = 26) @Stable private long jvmciHotSpotVMAddressEntryValueOffset; + @HotSpotVMData(index = 27) @Stable private long jvmciHotSpotVMAddressEntryArrayStride; final class VMAddresses implements Iterable { @@ -731,7 +708,7 @@ public class HotSpotVMConfig { private int index = 0; private Address currentEntry() { - return new Address(address + gHotSpotVMAddressEntryArrayStride * index); + return new Address(address + jvmciHotSpotVMAddressEntryArrayStride * index); } /** @@ -753,7 +730,7 @@ public class HotSpotVMConfig { final class Address extends AbstractConstant { Address(long address) { - super(address, gHotSpotVMAddressEntryNameOffset, gHotSpotVMAddressEntryValueOffset); + super(address, jvmciHotSpotVMAddressEntryNameOffset, jvmciHotSpotVMAddressEntryValueOffset); } @Override @@ -896,7 +873,7 @@ public class HotSpotVMConfig { @HotSpotVMFlag(name = "FlightRecorder", optional = true) @Stable public boolean flightRecorder; - @HotSpotVMField(name = "Universe::_collectedHeap", type = "CollectedHeap*", get = HotSpotVMField.Type.VALUE) @Stable private long universeCollectedHeap; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_collectedHeap", type = "CollectedHeap*", get = HotSpotVMField.Type.VALUE) @Stable private long universeCollectedHeap; @HotSpotVMField(name = "CollectedHeap::_total_collections", type = "unsigned int", get = HotSpotVMField.Type.OFFSET) @Stable private int collectedHeapTotalCollectionsOffset; public long gcTotalCollectionsAddress() { @@ -909,8 +886,8 @@ public class HotSpotVMConfig { @HotSpotVMFlag(name = "UseCompressedOops") @Stable public boolean useCompressedOops; @HotSpotVMFlag(name = "UseCompressedClassPointers") @Stable public boolean useCompressedClassPointers; - @HotSpotVMField(name = "Universe::_narrow_oop._base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowOopBase; - @HotSpotVMField(name = "Universe::_narrow_oop._shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowOopShift; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_narrow_oop_base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowOopBase; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_narrow_oop_shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowOopShift; @HotSpotVMFlag(name = "ObjectAlignmentInBytes") @Stable public int objectAlignment; public final int minObjAlignment() { @@ -922,16 +899,14 @@ public class HotSpotVMConfig { } @HotSpotVMType(name = "narrowKlass", get = HotSpotVMType.Type.SIZE) @Stable public int narrowKlassSize; - @HotSpotVMField(name = "Universe::_narrow_klass._base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowKlassBase; - @HotSpotVMField(name = "Universe::_narrow_klass._shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowKlassShift; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_narrow_klass_base", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long narrowKlassBase; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_narrow_klass_shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int narrowKlassShift; @HotSpotVMConstant(name = "LogKlassAlignmentInBytes") @Stable public int logKlassAlignment; // CPU capabilities @HotSpotVMFlag(name = "UseSSE") @Stable public int useSSE; @HotSpotVMFlag(name = "UseAVX", archs = {"amd64"}) @Stable public int useAVX; - @HotSpotVMField(name = "Abstract_VM_Version::_reserve_for_allocation_prefetch", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int abstractVmVersionReserveForAllocationPrefetch; - // X86 specific values @HotSpotVMField(name = "VM_Version::_cpuFeatures", type = "uint64_t", get = HotSpotVMField.Type.VALUE, archs = {"amd64"}) @Stable public long x86CPUFeatures; @HotSpotVMConstant(name = "VM_Version::CPU_CX8", archs = {"amd64"}) @Stable public long cpuCX8; @@ -1054,7 +1029,8 @@ public class HotSpotVMConfig { @HotSpotVMField(name = "InstanceKlass::_init_state", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassInitStateOffset; @HotSpotVMField(name = "InstanceKlass::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassConstantsOffset; @HotSpotVMField(name = "InstanceKlass::_fields", type = "Array*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassFieldsOffset; - @HotSpotVMField(name = "InstanceKlass::_vtable_len", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassVtableLengthOffset; + @HotSpotVMField(name = "CompilerToVM::Data::InstanceKlass_vtable_start_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int instanceKlassVtableStartOffset; + @HotSpotVMField(name = "CompilerToVM::Data::InstanceKlass_vtable_length_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int instanceKlassVtableLengthOffset; @HotSpotVMConstant(name = "InstanceKlass::linked") @Stable public int instanceKlassStateLinked; @HotSpotVMConstant(name = "InstanceKlass::fully_initialized") @Stable public int instanceKlassStateFullyInitialized; @@ -1063,12 +1039,7 @@ public class HotSpotVMConfig { * See {@code InstanceKlass::vtable_start_offset()}. */ public final int instanceKlassVtableStartOffset() { - return roundUp(instanceKlassSize, heapWordSize); - } - - // TODO use CodeUtil method once it's moved from NumUtil - private static int roundUp(int number, int mod) { - return ((number + mod - 1) / mod) * mod; + return instanceKlassVtableStartOffset * heapWordSize; } @HotSpotVMType(name = "arrayOopDesc", get = HotSpotVMType.Type.SIZE) @Stable public int arrayOopDescSize; @@ -1100,11 +1071,22 @@ public class HotSpotVMConfig { @HotSpotVMConstant(name = "FIELDINFO_TAG_SIZE") @Stable public int fieldInfoTagSize; + @HotSpotVMConstant(name = "JVM_ACC_MONITOR_MATCH") @Stable public int jvmAccMonitorMatch; + @HotSpotVMConstant(name = "JVM_ACC_HAS_MONITOR_BYTECODES") @Stable public int jvmAccHasMonitorBytecodes; + @HotSpotVMConstant(name = "JVM_ACC_HAS_FINALIZER") @Stable public int jvmAccHasFinalizer; @HotSpotVMConstant(name = "JVM_ACC_FIELD_INTERNAL") @Stable public int jvmAccFieldInternal; @HotSpotVMConstant(name = "JVM_ACC_FIELD_STABLE") @Stable public int jvmAccFieldStable; @HotSpotVMConstant(name = "JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE") @Stable public int jvmAccFieldHasGenericSignature; @HotSpotVMConstant(name = "JVM_ACC_WRITTEN_FLAGS") @Stable public int jvmAccWrittenFlags; + // Modifier.SYNTHETIC is not public so we get it via vmStructs. + @HotSpotVMConstant(name = "JVM_ACC_SYNTHETIC") @Stable public int jvmAccSynthetic; + + /** + * @see HotSpotResolvedObjectTypeImpl#createField + */ + @HotSpotVMConstant(name = "JVM_RECOGNIZED_FIELD_MODIFIERS") @Stable public int recognizedFieldModifiers; + @HotSpotVMField(name = "Thread::_tlab", type = "ThreadLocalAllocBuffer", get = HotSpotVMField.Type.OFFSET) @Stable public int threadTlabOffset; @HotSpotVMField(name = "JavaThread::_anchor", type = "JavaFrameAnchor", get = HotSpotVMField.Type.OFFSET) @Stable public int javaThreadAnchorOffset; @@ -1202,16 +1184,17 @@ public class HotSpotVMConfig { @HotSpotVMField(name = "OSThread::_interrupted", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int osThreadInterruptedOffset; - @HotSpotVMConstant(name = "markOopDesc::unlocked_value") @Stable public int unlockedMask; + @HotSpotVMConstant(name = "markOopDesc::hash_shift") @Stable public long markOopDescHashShift; + @HotSpotVMConstant(name = "markOopDesc::biased_lock_mask_in_place") @Stable public int biasedLockMaskInPlace; @HotSpotVMConstant(name = "markOopDesc::age_mask_in_place") @Stable public int ageMaskInPlace; @HotSpotVMConstant(name = "markOopDesc::epoch_mask_in_place") @Stable public int epochMaskInPlace; - - @HotSpotVMConstant(name = "markOopDesc::hash_shift") @Stable public long markOopDescHashShift; @HotSpotVMConstant(name = "markOopDesc::hash_mask") @Stable public long markOopDescHashMask; @HotSpotVMConstant(name = "markOopDesc::hash_mask_in_place") @Stable public long markOopDescHashMaskInPlace; + @HotSpotVMConstant(name = "markOopDesc::unlocked_value") @Stable public int unlockedMask; @HotSpotVMConstant(name = "markOopDesc::biased_lock_pattern") @Stable public int biasedLockPattern; + @HotSpotVMConstant(name = "markOopDesc::no_hash_in_place") @Stable public int markWordNoHashInPlace; @HotSpotVMConstant(name = "markOopDesc::no_lock_in_place") @Stable public int markWordNoLockInPlace; @@ -1247,6 +1230,11 @@ public class HotSpotVMConfig { @HotSpotVMField(name = "Method::_flags", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodFlagsOffset; @HotSpotVMField(name = "Method::_vtable_index", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodVtableIndexOffset; + @HotSpotVMField(name = "Method::_method_counters", type = "MethodCounters*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCountersOffset; + @HotSpotVMField(name = "Method::_method_data", type = "MethodData*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOffset; + @HotSpotVMField(name = "Method::_from_compiled_entry", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCompiledEntryOffset; + @HotSpotVMField(name = "Method::_code", type = "nmethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCodeOffset; + @HotSpotVMConstant(name = "Method::_jfr_towrite") @Stable public int methodFlagsJfrTowrite; @HotSpotVMConstant(name = "Method::_caller_sensitive") @Stable public int methodFlagsCallerSensitive; @HotSpotVMConstant(name = "Method::_force_inline") @Stable public int methodFlagsForceInline; @@ -1255,16 +1243,29 @@ public class HotSpotVMConfig { @HotSpotVMConstant(name = "Method::nonvirtual_vtable_index") @Stable public int nonvirtualVtableIndex; @HotSpotVMConstant(name = "Method::invalid_vtable_index") @Stable public int invalidVtableIndex; + @HotSpotVMField(name = "MethodCounters::_invocation_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int invocationCounterOffset; + @HotSpotVMField(name = "MethodCounters::_backedge_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int backedgeCounterOffset; + @HotSpotVMConstant(name = "InvocationCounter::count_increment") @Stable public int invocationCounterIncrement; + @HotSpotVMConstant(name = "InvocationCounter::count_shift") @Stable public int invocationCounterShift; + + @HotSpotVMField(name = "MethodData::_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataSize; + @HotSpotVMField(name = "MethodData::_data_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataDataSize; + @HotSpotVMField(name = "MethodData::_data[0]", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopDataOffset; + @HotSpotVMField(name = "MethodData::_trap_hist._array[0]", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopTrapHistoryOffset; + @HotSpotVMField(name = "MethodData::_jvmci_ir_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataIRSizeOffset; + + @HotSpotVMField(name = "nmethod::_verified_entry_point", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodEntryOffset; + @HotSpotVMField(name = "nmethod::_comp_level", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodCompLevelOffset; + + @HotSpotVMConstant(name = "CompLevel_full_optimization") @Stable public int compilationLevelFullOptimization; + @HotSpotVMConstant(name = "InvocationEntryBci") @Stable public int invocationEntryBci; @HotSpotVMField(name = "JVMCIEnv::_task", type = "CompileTask*", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciEnvTaskOffset; @HotSpotVMField(name = "JVMCIEnv::_jvmti_can_hotswap_or_post_breakpoint", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int jvmciEnvJvmtiCanHotswapOrPostBreakpointOffset; @HotSpotVMField(name = "CompileTask::_num_inlined_bytecodes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskNumInlinedBytecodesOffset; - /** - * See {@code Method::extra_stack_entries()}. - */ - @HotSpotVMConstant(name = "Method::extra_stack_entries_for_jsr292") @Stable public int extraStackEntries; + @HotSpotVMField(name = "CompilerToVM::Data::Method_extra_stack_entries", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int extraStackEntries; @HotSpotVMField(name = "ConstMethod::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodConstantsOffset; @HotSpotVMField(name = "ConstMethod::_flags", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int constMethodFlagsOffset; @@ -1325,72 +1326,39 @@ public class HotSpotVMConfig { @HotSpotVMConstant(name = "HeapWordSize") @Stable public int heapWordSize; @HotSpotVMType(name = "Symbol*", get = HotSpotVMType.Type.SIZE) @Stable public int symbolPointerSize; - @HotSpotVMField(name = "Symbol::_length", type = "unsigned short", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolLengthOffset; - @HotSpotVMField(name = "Symbol::_body[0]", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int symbolBodyOffset; @HotSpotVMField(name = "vmSymbols::_symbols[0]", type = "Symbol*", get = HotSpotVMField.Type.ADDRESS) @Stable public long vmSymbolsSymbols; @HotSpotVMConstant(name = "vmSymbols::FIRST_SID") @Stable public int vmSymbolsFirstSID; @HotSpotVMConstant(name = "vmSymbols::SID_LIMIT") @Stable public int vmSymbolsSIDLimit; - @HotSpotVMConstant(name = "JVM_ACC_HAS_FINALIZER") @Stable public int klassHasFinalizerFlag; - - // Modifier.SYNTHETIC is not public so we get it via vmStructs. - @HotSpotVMConstant(name = "JVM_ACC_SYNTHETIC") @Stable public int syntheticFlag; - - /** - * @see HotSpotResolvedObjectTypeImpl#createField - */ - @HotSpotVMConstant(name = "JVM_RECOGNIZED_FIELD_MODIFIERS") @Stable public int recognizedFieldModifiers; - /** * Bit pattern that represents a non-oop. Neither the high bits nor the low bits of this value * are allowed to look like (respectively) the high or low bits of a real oop. */ - @HotSpotVMField(name = "Universe::_non_oop_bits", type = "intptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long nonOopBits; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_non_oop_bits", type = "void*", get = HotSpotVMField.Type.VALUE) @Stable public long nonOopBits; @HotSpotVMField(name = "StubRoutines::_verify_oop_count", type = "jint", get = HotSpotVMField.Type.ADDRESS) @Stable public long verifyOopCounterAddress; - @HotSpotVMField(name = "Universe::_verify_oop_mask", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopMask; - @HotSpotVMField(name = "Universe::_verify_oop_bits", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopBits; - @HotSpotVMField(name = "Universe::_base_vtable_size", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int universeBaseVtableSize; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_verify_oop_mask", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopMask; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_verify_oop_bits", type = "uintptr_t", get = HotSpotVMField.Type.VALUE) @Stable public long verifyOopBits; + @HotSpotVMField(name = "CompilerToVM::Data::Universe_base_vtable_size", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int universeBaseVtableSize; public final int baseVtableLength() { return universeBaseVtableSize / vtableEntrySize; } - @HotSpotVMField(name = "CollectedHeap::_barrier_set", type = "BarrierSet*", get = HotSpotVMField.Type.OFFSET) @Stable public int collectedHeapBarrierSetOffset; - @HotSpotVMField(name = "HeapRegion::LogOfHRGrainBytes", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int logOfHRGrainBytes; - @HotSpotVMField(name = "BarrierSet::_fake_rtti", type = "BarrierSet::FakeRtti", get = HotSpotVMField.Type.OFFSET) @Stable private int barrierSetFakeRttiOffset; - @HotSpotVMConstant(name = "BarrierSet::CardTableModRef") @Stable public int barrierSetCardTableModRef; - @HotSpotVMConstant(name = "BarrierSet::CardTableForRS") @Stable public int barrierSetCardTableForRS; - @HotSpotVMConstant(name = "BarrierSet::CardTableExtension") @Stable public int barrierSetCardTableExtension; - @HotSpotVMConstant(name = "BarrierSet::G1SATBCT") @Stable public int barrierSetG1SATBCT; - @HotSpotVMConstant(name = "BarrierSet::G1SATBCTLogging") @Stable public int barrierSetG1SATBCTLogging; - @HotSpotVMConstant(name = "BarrierSet::ModRef") @Stable public int barrierSetModRef; - - @HotSpotVMField(name = "BarrierSet::FakeRtti::_concrete_tag", type = "BarrierSet::Name", get = HotSpotVMField.Type.OFFSET) @Stable private int fakeRttiConcreteTagOffset; - - @HotSpotVMField(name = "CardTableModRefBS::byte_map_base", type = "jbyte*", get = HotSpotVMField.Type.OFFSET) @Stable private int cardTableModRefBSByteMapBaseOffset; - @HotSpotVMConstant(name = "CardTableModRefBS::card_shift") @Stable public int cardTableModRefBSCardShift; - @HotSpotVMConstant(name = "CardTableModRefBS::dirty_card") @Stable public byte dirtyCardValue; @HotSpotVMConstant(name = "G1SATBCardTableModRefBS::g1_young_gen") @Stable public byte g1YoungCardValue; - private final long cardtableStartAddress; - private final int cardtableShift; + @HotSpotVMField(name = "CompilerToVM::Data::cardtable_start_address", type = "jbyte*", get = HotSpotVMField.Type.VALUE) @Stable private long cardtableStartAddress; + @HotSpotVMField(name = "CompilerToVM::Data::cardtable_shift", type = "int", get = HotSpotVMField.Type.VALUE) @Stable private int cardtableShift; public long cardtableStartAddress() { - if (cardtableStartAddress == -1) { - throw JVMCIError.shouldNotReachHere(); - } return cardtableStartAddress; } public int cardtableShift() { - if (cardtableShift == -1) { - throw JVMCIError.shouldNotReachHere(); - } return cardtableShift; } @@ -1421,34 +1389,12 @@ public class HotSpotVMConfig { @HotSpotVMField(name = "java_lang_Class::_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int klassOffset; @HotSpotVMField(name = "java_lang_Class::_array_klass_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int arrayKlassOffset; - @HotSpotVMField(name = "Method::_method_counters", type = "MethodCounters*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCountersOffset; - @HotSpotVMField(name = "Method::_method_data", type = "MethodData*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOffset; - @HotSpotVMField(name = "Method::_from_compiled_entry", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCompiledEntryOffset; - @HotSpotVMField(name = "Method::_code", type = "nmethod*", get = HotSpotVMField.Type.OFFSET) @Stable public int methodCodeOffset; - - @HotSpotVMField(name = "MethodCounters::_invocation_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int invocationCounterOffset; - @HotSpotVMField(name = "MethodCounters::_backedge_counter", type = "InvocationCounter", get = HotSpotVMField.Type.OFFSET) @Stable public int backedgeCounterOffset; - @HotSpotVMConstant(name = "InvocationCounter::count_increment") @Stable public int invocationCounterIncrement; - @HotSpotVMConstant(name = "InvocationCounter::count_shift") @Stable public int invocationCounterShift; - - @HotSpotVMField(name = "MethodData::_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataSize; - @HotSpotVMField(name = "MethodData::_data_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataDataSize; - @HotSpotVMField(name = "MethodData::_data[0]", type = "intptr_t", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopDataOffset; - @HotSpotVMField(name = "MethodData::_trap_hist._array[0]", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataOopTrapHistoryOffset; - @HotSpotVMField(name = "MethodData::_jvmci_ir_size", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int methodDataIRSizeOffset; - - @HotSpotVMField(name = "nmethod::_verified_entry_point", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodEntryOffset; - @HotSpotVMField(name = "nmethod::_comp_level", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int nmethodCompLevelOffset; - - @HotSpotVMConstant(name = "CompLevel_full_optimization") @Stable public int compilationLevelFullOptimization; - @HotSpotVMType(name = "BasicLock", get = HotSpotVMType.Type.SIZE) @Stable public int basicLockSize; @HotSpotVMField(name = "BasicLock::_displaced_header", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int basicLockDisplacedHeaderOffset; @HotSpotVMField(name = "Thread::_allocated_bytes", type = "jlong", get = HotSpotVMField.Type.OFFSET) @Stable public int threadAllocatedBytesOffset; @HotSpotVMFlag(name = "TLABWasteIncrement") @Stable public int tlabRefillWasteIncrement; - @HotSpotVMManual(name = "ThreadLocalAllocBuffer::alignment_reserve()") @Stable public int tlabAlignmentReserve; @HotSpotVMField(name = "ThreadLocalAllocBuffer::_start", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferStartOffset; @HotSpotVMField(name = "ThreadLocalAllocBuffer::_end", type = "HeapWord*", get = HotSpotVMField.Type.OFFSET) @Stable private int threadLocalAllocBufferEndOffset; @@ -1496,22 +1442,14 @@ public class HotSpotVMConfig { return threadTlabOffset + threadLocalAllocBufferPfTopOffset; } - /** - * See: {@code ThreadLocalAllocBuffer::end_reserve()}. - */ - public final int threadLocalAllocBufferEndReserve() { - final int typeSizeInBytes = roundUp(arrayOopDescLengthOffset() + Integer.BYTES, heapWordSize); - // T_INT arrays need not be 8 byte aligned. - final int reserveSize = typeSizeInBytes / heapWordSize; - return Integer.max(reserveSize, abstractVmVersionReserveForAllocationPrefetch); - } + @HotSpotVMField(name = "CompilerToVM::Data::ThreadLocalAllocBuffer_alignment_reserve", type = "size_t", get = HotSpotVMField.Type.VALUE) @Stable public int tlabAlignmentReserve; @HotSpotVMFlag(name = "TLABStats") @Stable public boolean tlabStats; // FIXME This is only temporary until the GC code is changed. - @HotSpotVMField(name = "CompilerToVM::_supports_inline_contig_alloc", type = "bool", get = HotSpotVMField.Type.VALUE) @Stable public boolean inlineContiguousAllocationSupported; - @HotSpotVMField(name = "CompilerToVM::_heap_end_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapEndAddress; - @HotSpotVMField(name = "CompilerToVM::_heap_top_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapTopAddress; + @HotSpotVMField(name = "CompilerToVM::Data::_supports_inline_contig_alloc", type = "bool", get = HotSpotVMField.Type.VALUE) @Stable public boolean inlineContiguousAllocationSupported; + @HotSpotVMField(name = "CompilerToVM::Data::_heap_end_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapEndAddress; + @HotSpotVMField(name = "CompilerToVM::Data::_heap_top_addr", type = "HeapWord**", get = HotSpotVMField.Type.VALUE) @Stable public long heapTopAddress; /** * The DataLayout header size is the same as the cell size. @@ -1542,19 +1480,11 @@ public class HotSpotVMConfig { @HotSpotVMFlag(name = "TypeProfileWidth") @Stable public int typeProfileWidth; @HotSpotVMFlag(name = "MethodProfileWidth") @Stable public int methodProfileWidth; - @HotSpotVMField(name = "CodeBlob::_code_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int codeBlobCodeOffsetOffset; - @HotSpotVMField(name = "DeoptimizationBlob::_unpack_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int deoptimizationBlobUnpackOffsetOffset; - @HotSpotVMField(name = "DeoptimizationBlob::_uncommon_trap_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int deoptimizationBlobUncommonTrapOffsetOffset; + @HotSpotVMField(name = "CompilerToVM::Data::SharedRuntime_ic_miss_stub", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long inlineCacheMissStub; + @HotSpotVMField(name = "CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long handleWrongMethodStub; - @HotSpotVMField(name = "SharedRuntime::_ic_miss_blob", type = "RuntimeStub*", get = HotSpotVMField.Type.VALUE) @Stable private long inlineCacheMissBlob; - @HotSpotVMField(name = "SharedRuntime::_wrong_method_blob", type = "RuntimeStub*", get = HotSpotVMField.Type.VALUE) @Stable private long wrongMethodBlob; - @HotSpotVMField(name = "SharedRuntime::_deopt_blob", type = "DeoptimizationBlob*", get = HotSpotVMField.Type.VALUE) @Stable private long deoptBlob; - - @HotSpotVMManual(name = "SharedRuntime::get_ic_miss_stub()") public final long inlineCacheMissStub; - @HotSpotVMManual(name = "SharedRuntime::get_handle_wrong_method_stub()") public final long handleWrongMethodStub; - - @HotSpotVMManual(name = "SharedRuntime::deopt_blob()->unpack()") public final long handleDeoptStub; - @HotSpotVMManual(name = "SharedRuntime::deopt_blob()->uncommon_trap()") public final long uncommonTrapStub; + @HotSpotVMField(name = "CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long handleDeoptStub; + @HotSpotVMField(name = "CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long uncommonTrapStub; @HotSpotVMField(name = "CodeCache::_low_bound", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long codeCacheLowBound; @HotSpotVMField(name = "CodeCache::_high_bound", type = "address", get = HotSpotVMField.Type.VALUE) @Stable public long codeCacheHighBound; @@ -1717,9 +1647,6 @@ public class HotSpotVMConfig { return "unknown"; } - @HotSpotVMConstant(name = "CompilerToVM::KLASS_TAG") @Stable public int compilerToVMKlassTag; - @HotSpotVMConstant(name = "CompilerToVM::SYMBOL_TAG") @Stable public int compilerToVMSymbolTag; - // Checkstyle: stop @HotSpotVMConstant(name = "CodeInstaller::VERIFIED_ENTRY") @Stable public int MARKID_VERIFIED_ENTRY; @HotSpotVMConstant(name = "CodeInstaller::UNVERIFIED_ENTRY") @Stable public int MARKID_UNVERIFIED_ENTRY; @@ -1756,7 +1683,6 @@ public class HotSpotVMConfig { @HotSpotVMConstant(name = "ArrayData::array_len_off_set") @Stable public int arrayDataArrayLenOffset; @HotSpotVMConstant(name = "ArrayData::array_start_off_set") @Stable public int arrayDataArrayStartOffset; @HotSpotVMConstant(name = "MultiBranchData::per_case_cell_count") @Stable public int multiBranchDataPerCaseCellCount; - // Checkstyle: resume private boolean check() { diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMManual.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMManual.java deleted file mode 100644 index 91ddf950879..00000000000 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspotvmconfig/src/jdk/vm/ci/hotspotvmconfig/HotSpotVMManual.java +++ /dev/null @@ -1,44 +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. - */ -package jdk.vm.ci.hotspotvmconfig; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Annotates a field in HotSpotVMConfig which is not read from the VM but is calculated manually. - */ -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface HotSpotVMManual { - - /** - * Returns the name associated with that field. - * - * @return name associated with field - */ - String name(); - -} diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 192d11ccede..1aa88b399db 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -240,6 +240,7 @@ class java_lang_String : AllStatic { class java_lang_Class : AllStatic { friend class VMStructs; + friend class JVMCIVMStructs; private: // The fake offsets are added by the class loader when java.lang.Class is loaded diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index 6fff569a762..805bb45162c 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -1328,6 +1328,7 @@ class vmSymbols: AllStatic { friend class vmIntrinsics; friend class VMStructs; + friend class JVMCIVMStructs; public: // enum for figuring positions and size of array holding Symbol*s enum SID { diff --git a/hotspot/src/share/vm/code/codeBlob.hpp b/hotspot/src/share/vm/code/codeBlob.hpp index cf846940b60..a4a4cab7c8b 100644 --- a/hotspot/src/share/vm/code/codeBlob.hpp +++ b/hotspot/src/share/vm/code/codeBlob.hpp @@ -64,6 +64,7 @@ class DeoptimizationBlob; class CodeBlob VALUE_OBJ_CLASS_SPEC { friend class VMStructs; + friend class JVMCIVMStructs; friend class CodeCacheDumper; private: @@ -374,6 +375,7 @@ class SingletonBlob: public CodeBlob { class DeoptimizationBlob: public SingletonBlob { friend class VMStructs; + friend class JVMCIVMStructs; private: int _unpack_offset; int _unpack_with_exception; diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp index 88594bd80a7..a3da713c9e5 100644 --- a/hotspot/src/share/vm/code/codeCache.hpp +++ b/hotspot/src/share/vm/code/codeCache.hpp @@ -76,6 +76,7 @@ class DepChange; class CodeCache : AllStatic { friend class VMStructs; + friend class JVMCIVMStructs; friend class NMethodIterator; friend class WhiteBox; friend class CodeCacheLoader; diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 2305f51bc24..f38ed2edb36 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -113,6 +113,7 @@ class xmlStream; class nmethod : public CodeBlob { friend class VMStructs; + friend class JVMCIVMStructs; friend class NMethodSweeper; friend class CodeCache; // scavengable oops private: diff --git a/hotspot/src/share/vm/compiler/compileTask.hpp b/hotspot/src/share/vm/compiler/compileTask.hpp index 1ec57bd00ab..17f77b34dee 100644 --- a/hotspot/src/share/vm/compiler/compileTask.hpp +++ b/hotspot/src/share/vm/compiler/compileTask.hpp @@ -38,6 +38,7 @@ class CompileTask : public CHeapObj { friend class VMStructs; + friend class JVMCIVMStructs; private: static CompileTask* _task_free_list; diff --git a/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp b/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp index 1fad2b64637..b790d40a78c 100644 --- a/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp +++ b/hotspot/src/share/vm/gc/g1/vmStructs_g1.hpp @@ -70,27 +70,6 @@ #define VM_INT_CONSTANTS_G1(declare_constant, declare_constant_with_value) \ - \ - JVMCI_ONLY( \ - declare_constant_with_value( \ - "dirtyCardQueueBufferOffset", \ - in_bytes(DirtyCardQueue::byte_offset_of_buf())) \ - declare_constant_with_value( \ - "dirtyCardQueueIndexOffset", \ - in_bytes(DirtyCardQueue::byte_offset_of_index())) \ - ) /* JVMCI_ONLY */ \ - \ - JVMCI_ONLY( \ - declare_constant_with_value( \ - "satbMarkQueueBufferOffset", \ - in_bytes(SATBMarkQueue::byte_offset_of_buf())) \ - declare_constant_with_value( \ - "satbMarkQueueIndexOffset", \ - in_bytes(SATBMarkQueue::byte_offset_of_index())) \ - declare_constant_with_value( \ - "satbMarkQueueActiveOffset", \ - in_bytes(SATBMarkQueue::byte_offset_of_active())) \ - ) /* JVMCI_ONLY */ \ #define VM_TYPES_G1(declare_type, declare_toplevel_type) \ diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp index d12941b14fe..02de82c7b83 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp @@ -81,6 +81,7 @@ class GCHeapLog : public EventLogBase { // class CollectedHeap : public CHeapObj { friend class VMStructs; + friend class JVMCIVMStructs; friend class IsGCActiveMark; // Block structured external access to _is_gc_active private: diff --git a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.hpp b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.hpp index 60e05dcab26..eca56006510 100644 --- a/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.hpp +++ b/hotspot/src/share/vm/gc/shared/threadLocalAllocBuffer.hpp @@ -39,6 +39,7 @@ class GlobalTLABStats; // used to make it available for such multiplexing. class ThreadLocalAllocBuffer: public CHeapObj { friend class VMStructs; + friend class JVMCIVMStructs; private: HeapWord* _start; // address of TLAB HeapWord* _top; // address after last allocation diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp index 394d263f668..1157759d0ed 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp @@ -89,7 +89,7 @@ private: * This class handles the conversion from a InstalledCode to a CodeBlob or an nmethod. */ class CodeInstaller : public StackObj { - friend class VMStructs; + friend class JVMCIVMStructs; private: enum MarkId { VERIFIED_ENTRY = 1, diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp index 694513cc4a7..2205ff479fd 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp @@ -43,6 +43,7 @@ #include "jvmci/jvmciEnv.hpp" #include "jvmci/jvmciJavaClasses.hpp" #include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/vmStructs_jvmci.hpp" #include "gc/g1/heapRegion.hpp" #include "runtime/javaCalls.hpp" #include "runtime/deoptimization.hpp" @@ -85,88 +86,160 @@ oop CompilerToVM::get_jvmci_type(KlassHandle klass, TRAPS) { } extern "C" { -extern VMStructEntry* gHotSpotVMStructs; -extern uint64_t gHotSpotVMStructEntryTypeNameOffset; -extern uint64_t gHotSpotVMStructEntryFieldNameOffset; -extern uint64_t gHotSpotVMStructEntryTypeStringOffset; -extern uint64_t gHotSpotVMStructEntryIsStaticOffset; -extern uint64_t gHotSpotVMStructEntryOffsetOffset; -extern uint64_t gHotSpotVMStructEntryAddressOffset; -extern uint64_t gHotSpotVMStructEntryArrayStride; +extern VMStructEntry* jvmciHotSpotVMStructs; +extern uint64_t jvmciHotSpotVMStructEntryTypeNameOffset; +extern uint64_t jvmciHotSpotVMStructEntryFieldNameOffset; +extern uint64_t jvmciHotSpotVMStructEntryTypeStringOffset; +extern uint64_t jvmciHotSpotVMStructEntryIsStaticOffset; +extern uint64_t jvmciHotSpotVMStructEntryOffsetOffset; +extern uint64_t jvmciHotSpotVMStructEntryAddressOffset; +extern uint64_t jvmciHotSpotVMStructEntryArrayStride; -extern VMTypeEntry* gHotSpotVMTypes; -extern uint64_t gHotSpotVMTypeEntryTypeNameOffset; -extern uint64_t gHotSpotVMTypeEntrySuperclassNameOffset; -extern uint64_t gHotSpotVMTypeEntryIsOopTypeOffset; -extern uint64_t gHotSpotVMTypeEntryIsIntegerTypeOffset; -extern uint64_t gHotSpotVMTypeEntryIsUnsignedOffset; -extern uint64_t gHotSpotVMTypeEntrySizeOffset; -extern uint64_t gHotSpotVMTypeEntryArrayStride; +extern VMTypeEntry* jvmciHotSpotVMTypes; +extern uint64_t jvmciHotSpotVMTypeEntryTypeNameOffset; +extern uint64_t jvmciHotSpotVMTypeEntrySuperclassNameOffset; +extern uint64_t jvmciHotSpotVMTypeEntryIsOopTypeOffset; +extern uint64_t jvmciHotSpotVMTypeEntryIsIntegerTypeOffset; +extern uint64_t jvmciHotSpotVMTypeEntryIsUnsignedOffset; +extern uint64_t jvmciHotSpotVMTypeEntrySizeOffset; +extern uint64_t jvmciHotSpotVMTypeEntryArrayStride; -extern VMIntConstantEntry* gHotSpotVMIntConstants; -extern uint64_t gHotSpotVMIntConstantEntryNameOffset; -extern uint64_t gHotSpotVMIntConstantEntryValueOffset; -extern uint64_t gHotSpotVMIntConstantEntryArrayStride; +extern VMIntConstantEntry* jvmciHotSpotVMIntConstants; +extern uint64_t jvmciHotSpotVMIntConstantEntryNameOffset; +extern uint64_t jvmciHotSpotVMIntConstantEntryValueOffset; +extern uint64_t jvmciHotSpotVMIntConstantEntryArrayStride; -extern VMLongConstantEntry* gHotSpotVMLongConstants; -extern uint64_t gHotSpotVMLongConstantEntryNameOffset; -extern uint64_t gHotSpotVMLongConstantEntryValueOffset; -extern uint64_t gHotSpotVMLongConstantEntryArrayStride; +extern VMLongConstantEntry* jvmciHotSpotVMLongConstants; +extern uint64_t jvmciHotSpotVMLongConstantEntryNameOffset; +extern uint64_t jvmciHotSpotVMLongConstantEntryValueOffset; +extern uint64_t jvmciHotSpotVMLongConstantEntryArrayStride; -extern VMAddressEntry* gHotSpotVMAddresses; -extern uint64_t gHotSpotVMAddressEntryNameOffset; -extern uint64_t gHotSpotVMAddressEntryValueOffset; -extern uint64_t gHotSpotVMAddressEntryArrayStride; +extern VMAddressEntry* jvmciHotSpotVMAddresses; +extern uint64_t jvmciHotSpotVMAddressEntryNameOffset; +extern uint64_t jvmciHotSpotVMAddressEntryValueOffset; +extern uint64_t jvmciHotSpotVMAddressEntryArrayStride; } -// FIXME This is only temporary until the GC code is changed. -bool CompilerToVM::_supports_inline_contig_alloc; -HeapWord** CompilerToVM::_heap_end_addr; -HeapWord** CompilerToVM::_heap_top_addr; +int CompilerToVM::Data::InstanceKlass_vtable_start_offset; +int CompilerToVM::Data::InstanceKlass_vtable_length_offset; + +int CompilerToVM::Data::Method_extra_stack_entries; + +address CompilerToVM::Data::SharedRuntime_ic_miss_stub; +address CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub; +address CompilerToVM::Data::SharedRuntime_deopt_blob_unpack; +address CompilerToVM::Data::SharedRuntime_deopt_blob_uncommon_trap; + +size_t CompilerToVM::Data::ThreadLocalAllocBuffer_alignment_reserve; + +CollectedHeap* CompilerToVM::Data::Universe_collectedHeap; +int CompilerToVM::Data::Universe_base_vtable_size; +address CompilerToVM::Data::Universe_narrow_oop_base; +int CompilerToVM::Data::Universe_narrow_oop_shift; +address CompilerToVM::Data::Universe_narrow_klass_base; +int CompilerToVM::Data::Universe_narrow_klass_shift; +void* CompilerToVM::Data::Universe_non_oop_bits; +uintptr_t CompilerToVM::Data::Universe_verify_oop_mask; +uintptr_t CompilerToVM::Data::Universe_verify_oop_bits; + +bool CompilerToVM::Data::_supports_inline_contig_alloc; +HeapWord** CompilerToVM::Data::_heap_end_addr; +HeapWord** CompilerToVM::Data::_heap_top_addr; + +jbyte* CompilerToVM::Data::cardtable_start_address; +int CompilerToVM::Data::cardtable_shift; + +void CompilerToVM::Data::initialize() { + InstanceKlass_vtable_start_offset = InstanceKlass::vtable_start_offset(); + InstanceKlass_vtable_length_offset = InstanceKlass::vtable_length_offset() * HeapWordSize; + + Method_extra_stack_entries = Method::extra_stack_entries(); + + SharedRuntime_ic_miss_stub = SharedRuntime::get_ic_miss_stub(); + SharedRuntime_handle_wrong_method_stub = SharedRuntime::get_handle_wrong_method_stub(); + SharedRuntime_deopt_blob_unpack = SharedRuntime::deopt_blob()->unpack(); + SharedRuntime_deopt_blob_uncommon_trap = SharedRuntime::deopt_blob()->uncommon_trap(); + + ThreadLocalAllocBuffer_alignment_reserve = ThreadLocalAllocBuffer::alignment_reserve(); + + Universe_collectedHeap = Universe::heap(); + Universe_base_vtable_size = Universe::base_vtable_size(); + Universe_narrow_oop_base = Universe::narrow_oop_base(); + Universe_narrow_oop_shift = Universe::narrow_oop_shift(); + Universe_narrow_klass_base = Universe::narrow_klass_base(); + Universe_narrow_klass_shift = Universe::narrow_klass_shift(); + Universe_non_oop_bits = Universe::non_oop_word(); + Universe_verify_oop_mask = Universe::verify_oop_mask(); + Universe_verify_oop_bits = Universe::verify_oop_bits(); + + _supports_inline_contig_alloc = Universe::heap()->supports_inline_contig_alloc(); + _heap_end_addr = _supports_inline_contig_alloc ? Universe::heap()->end_addr() : (HeapWord**) -1; + _heap_top_addr = _supports_inline_contig_alloc ? Universe::heap()->top_addr() : (HeapWord**) -1; + + BarrierSet* bs = Universe::heap()->barrier_set(); + switch (bs->kind()) { + case BarrierSet::CardTableModRef: + case BarrierSet::CardTableForRS: + case BarrierSet::CardTableExtension: + case BarrierSet::G1SATBCT: + case BarrierSet::G1SATBCTLogging: { + jbyte* base = barrier_set_cast(bs)->byte_map_base; + assert(base != 0, "unexpected byte_map_base"); + cardtable_start_address = base; + cardtable_shift = CardTableModRefBS::card_shift; + break; + } + case BarrierSet::ModRef: + cardtable_start_address = 0; + cardtable_shift = 0; + // No post barriers + break; + default: + ShouldNotReachHere(); + break; + } +} /** - * We put all gHotSpotVM values in an array so we can read them easily from Java. + * We put all jvmciHotSpotVM values in an array so we can read them easily from Java. */ static uintptr_t ciHotSpotVMData[28]; C2V_VMENTRY(jlong, initializeConfiguration, (JNIEnv *env, jobject)) - ciHotSpotVMData[0] = (uintptr_t) gHotSpotVMStructs; - ciHotSpotVMData[1] = gHotSpotVMStructEntryTypeNameOffset; - ciHotSpotVMData[2] = gHotSpotVMStructEntryFieldNameOffset; - ciHotSpotVMData[3] = gHotSpotVMStructEntryTypeStringOffset; - ciHotSpotVMData[4] = gHotSpotVMStructEntryIsStaticOffset; - ciHotSpotVMData[5] = gHotSpotVMStructEntryOffsetOffset; - ciHotSpotVMData[6] = gHotSpotVMStructEntryAddressOffset; - ciHotSpotVMData[7] = gHotSpotVMStructEntryArrayStride; + ciHotSpotVMData[0] = (uintptr_t) jvmciHotSpotVMStructs; + ciHotSpotVMData[1] = jvmciHotSpotVMStructEntryTypeNameOffset; + ciHotSpotVMData[2] = jvmciHotSpotVMStructEntryFieldNameOffset; + ciHotSpotVMData[3] = jvmciHotSpotVMStructEntryTypeStringOffset; + ciHotSpotVMData[4] = jvmciHotSpotVMStructEntryIsStaticOffset; + ciHotSpotVMData[5] = jvmciHotSpotVMStructEntryOffsetOffset; + ciHotSpotVMData[6] = jvmciHotSpotVMStructEntryAddressOffset; + ciHotSpotVMData[7] = jvmciHotSpotVMStructEntryArrayStride; - ciHotSpotVMData[8] = (uintptr_t) gHotSpotVMTypes; - ciHotSpotVMData[9] = gHotSpotVMTypeEntryTypeNameOffset; - ciHotSpotVMData[10] = gHotSpotVMTypeEntrySuperclassNameOffset; - ciHotSpotVMData[11] = gHotSpotVMTypeEntryIsOopTypeOffset; - ciHotSpotVMData[12] = gHotSpotVMTypeEntryIsIntegerTypeOffset; - ciHotSpotVMData[13] = gHotSpotVMTypeEntryIsUnsignedOffset; - ciHotSpotVMData[14] = gHotSpotVMTypeEntrySizeOffset; - ciHotSpotVMData[15] = gHotSpotVMTypeEntryArrayStride; + ciHotSpotVMData[8] = (uintptr_t) jvmciHotSpotVMTypes; + ciHotSpotVMData[9] = jvmciHotSpotVMTypeEntryTypeNameOffset; + ciHotSpotVMData[10] = jvmciHotSpotVMTypeEntrySuperclassNameOffset; + ciHotSpotVMData[11] = jvmciHotSpotVMTypeEntryIsOopTypeOffset; + ciHotSpotVMData[12] = jvmciHotSpotVMTypeEntryIsIntegerTypeOffset; + ciHotSpotVMData[13] = jvmciHotSpotVMTypeEntryIsUnsignedOffset; + ciHotSpotVMData[14] = jvmciHotSpotVMTypeEntrySizeOffset; + ciHotSpotVMData[15] = jvmciHotSpotVMTypeEntryArrayStride; - ciHotSpotVMData[16] = (uintptr_t) gHotSpotVMIntConstants; - ciHotSpotVMData[17] = gHotSpotVMIntConstantEntryNameOffset; - ciHotSpotVMData[18] = gHotSpotVMIntConstantEntryValueOffset; - ciHotSpotVMData[19] = gHotSpotVMIntConstantEntryArrayStride; + ciHotSpotVMData[16] = (uintptr_t) jvmciHotSpotVMIntConstants; + ciHotSpotVMData[17] = jvmciHotSpotVMIntConstantEntryNameOffset; + ciHotSpotVMData[18] = jvmciHotSpotVMIntConstantEntryValueOffset; + ciHotSpotVMData[19] = jvmciHotSpotVMIntConstantEntryArrayStride; - ciHotSpotVMData[20] = (uintptr_t) gHotSpotVMLongConstants; - ciHotSpotVMData[21] = gHotSpotVMLongConstantEntryNameOffset; - ciHotSpotVMData[22] = gHotSpotVMLongConstantEntryValueOffset; - ciHotSpotVMData[23] = gHotSpotVMLongConstantEntryArrayStride; + ciHotSpotVMData[20] = (uintptr_t) jvmciHotSpotVMLongConstants; + ciHotSpotVMData[21] = jvmciHotSpotVMLongConstantEntryNameOffset; + ciHotSpotVMData[22] = jvmciHotSpotVMLongConstantEntryValueOffset; + ciHotSpotVMData[23] = jvmciHotSpotVMLongConstantEntryArrayStride; - ciHotSpotVMData[24] = (uintptr_t) gHotSpotVMAddresses; - ciHotSpotVMData[25] = gHotSpotVMAddressEntryNameOffset; - ciHotSpotVMData[26] = gHotSpotVMAddressEntryValueOffset; - ciHotSpotVMData[27] = gHotSpotVMAddressEntryArrayStride; + ciHotSpotVMData[24] = (uintptr_t) jvmciHotSpotVMAddresses; + ciHotSpotVMData[25] = jvmciHotSpotVMAddressEntryNameOffset; + ciHotSpotVMData[26] = jvmciHotSpotVMAddressEntryValueOffset; + ciHotSpotVMData[27] = jvmciHotSpotVMAddressEntryArrayStride; - // FIXME This is only temporary until the GC code is changed. - CompilerToVM::_supports_inline_contig_alloc = Universe::heap()->supports_inline_contig_alloc(); - CompilerToVM::_heap_end_addr = CompilerToVM::_supports_inline_contig_alloc ? Universe::heap()->end_addr() : (HeapWord**) -1; - CompilerToVM::_heap_top_addr = CompilerToVM::_supports_inline_contig_alloc ? Universe::heap()->top_addr() : (HeapWord**) -1; + CompilerToVM::Data::initialize(); return (jlong) (address) &ciHotSpotVMData; C2V_END diff --git a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp index 35f17689f1e..1947324556b 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp @@ -29,28 +29,45 @@ #include "jvmci/jvmciJavaClasses.hpp" class CompilerToVM { -public: - /** - * Tag bits used by lookupKlassInPool to distinguish the types in Java. - */ - enum Tags { - KLASS_TAG = 0x0, - SYMBOL_TAG = 0x1 + public: + class Data { + friend class JVMCIVMStructs; + + private: + static int InstanceKlass_vtable_start_offset; + static int InstanceKlass_vtable_length_offset; + + static int Method_extra_stack_entries; + + static address SharedRuntime_ic_miss_stub; + static address SharedRuntime_handle_wrong_method_stub; + static address SharedRuntime_deopt_blob_unpack; + static address SharedRuntime_deopt_blob_uncommon_trap; + + static size_t ThreadLocalAllocBuffer_alignment_reserve; + + static CollectedHeap* Universe_collectedHeap; + static int Universe_base_vtable_size; + static address Universe_narrow_oop_base; + static int Universe_narrow_oop_shift; + static address Universe_narrow_klass_base; + static int Universe_narrow_klass_shift; + static uintptr_t Universe_verify_oop_mask; + static uintptr_t Universe_verify_oop_bits; + static void* Universe_non_oop_bits; + + static bool _supports_inline_contig_alloc; + static HeapWord** _heap_end_addr; + static HeapWord** _heap_top_addr; + + static jbyte* cardtable_start_address; + static int cardtable_shift; + + public: + static void initialize(); }; - // FIXME This is only temporary until the GC code is changed. - static bool _supports_inline_contig_alloc; - static HeapWord** _heap_end_addr; - static HeapWord** _heap_top_addr; - - static intptr_t tag_pointer(Klass* klass) { - return ((intptr_t) klass) | KLASS_TAG; - } - - static intptr_t tag_pointer(Symbol* symbol) { - return ((intptr_t) symbol) | SYMBOL_TAG; - } - + public: static JNINativeMethod methods[]; static int methods_count(); diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp index 173729259fe..2bc95d3308c 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.hpp @@ -53,6 +53,7 @@ class CompileTask; class JVMCIEnv : StackObj { CI_PACKAGE_ACCESS_TO + friend class JVMCIVMStructs; friend class CompileBroker; friend class Dependencies; // for get_object, during logging diff --git a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp index afcbdf27f82..893a576699f 100644 --- a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp @@ -813,10 +813,6 @@ JVM_ENTRY(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass)) { ThreadToNativeFromVM trans(thread); - - // Ensure _non_oop_bits is initialized - Universe::non_oop_word(); - env->RegisterNatives(c2vmClass, CompilerToVM::methods, CompilerToVM::methods_count()); } JVM_END diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp new file mode 100644 index 00000000000..fdd816a1929 --- /dev/null +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp @@ -0,0 +1,849 @@ +/* + * 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 "code/codeBlob.hpp" +#include "compiler/abstractCompiler.hpp" +#include "compiler/compileBroker.hpp" +#include "jvmci/jvmciCodeInstaller.hpp" +#include "jvmci/jvmciCompilerToVM.hpp" +#include "jvmci/jvmciEnv.hpp" +#include "jvmci/jvmciRuntime.hpp" +#include "jvmci/vmStructs_jvmci.hpp" +#include "oops/oop.hpp" +#include "oops/objArrayKlass.hpp" +#include "runtime/globals.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/thread.hpp" +#include "runtime/vm_version.hpp" + +#if INCLUDE_ALL_GCS +#include "gc/g1/g1SATBCardTableModRefBS.hpp" +#include "gc/g1/heapRegion.hpp" +#endif + + +#define VM_STRUCTS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field) \ + static_field(CompilerToVM::Data, InstanceKlass_vtable_start_offset, int) \ + static_field(CompilerToVM::Data, InstanceKlass_vtable_length_offset, int) \ + \ + static_field(CompilerToVM::Data, Method_extra_stack_entries, int) \ + \ + static_field(CompilerToVM::Data, SharedRuntime_ic_miss_stub, address) \ + static_field(CompilerToVM::Data, SharedRuntime_handle_wrong_method_stub, address) \ + static_field(CompilerToVM::Data, SharedRuntime_deopt_blob_unpack, address) \ + static_field(CompilerToVM::Data, SharedRuntime_deopt_blob_uncommon_trap, address) \ + \ + static_field(CompilerToVM::Data, ThreadLocalAllocBuffer_alignment_reserve, size_t) \ + \ + static_field(CompilerToVM::Data, Universe_collectedHeap, CollectedHeap*) \ + static_field(CompilerToVM::Data, Universe_base_vtable_size, int) \ + static_field(CompilerToVM::Data, Universe_narrow_oop_base, address) \ + static_field(CompilerToVM::Data, Universe_narrow_oop_shift, int) \ + static_field(CompilerToVM::Data, Universe_narrow_klass_base, address) \ + static_field(CompilerToVM::Data, Universe_narrow_klass_shift, int) \ + static_field(CompilerToVM::Data, Universe_non_oop_bits, void*) \ + static_field(CompilerToVM::Data, Universe_verify_oop_mask, uintptr_t) \ + static_field(CompilerToVM::Data, Universe_verify_oop_bits, uintptr_t) \ + \ + static_field(CompilerToVM::Data, _supports_inline_contig_alloc, bool) \ + static_field(CompilerToVM::Data, _heap_end_addr, HeapWord**) \ + static_field(CompilerToVM::Data, _heap_top_addr, HeapWord**) \ + \ + static_field(CompilerToVM::Data, cardtable_start_address, jbyte*) \ + static_field(CompilerToVM::Data, cardtable_shift, int) \ + \ + nonstatic_field(Array, _length, int) \ + unchecked_nonstatic_field(Array, _data, sizeof(u1)) \ + unchecked_nonstatic_field(Array, _data, sizeof(u2)) \ + nonstatic_field(Array, _length, int) \ + nonstatic_field(Array, _data[0], Klass*) \ + \ + volatile_nonstatic_field(BasicLock, _displaced_header, markOop) \ + \ + static_field(CodeCache, _low_bound, address) \ + static_field(CodeCache, _high_bound, address) \ + \ + nonstatic_field(CollectedHeap, _total_collections, unsigned int) \ + \ + nonstatic_field(CompileTask, _num_inlined_bytecodes, int) \ + \ + nonstatic_field(ConstantPool, _tags, Array*) \ + nonstatic_field(ConstantPool, _pool_holder, InstanceKlass*) \ + nonstatic_field(ConstantPool, _length, int) \ + \ + nonstatic_field(ConstMethod, _constants, ConstantPool*) \ + nonstatic_field(ConstMethod, _flags, u2) \ + nonstatic_field(ConstMethod, _code_size, u2) \ + nonstatic_field(ConstMethod, _name_index, u2) \ + nonstatic_field(ConstMethod, _signature_index, u2) \ + nonstatic_field(ConstMethod, _max_stack, u2) \ + nonstatic_field(ConstMethod, _max_locals, u2) \ + \ + nonstatic_field(DataLayout, _header._struct._tag, u1) \ + nonstatic_field(DataLayout, _header._struct._flags, u1) \ + nonstatic_field(DataLayout, _header._struct._bci, u2) \ + nonstatic_field(DataLayout, _cells[0], intptr_t) \ + \ + nonstatic_field(Deoptimization::UnrollBlock, _size_of_deoptimized_frame, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _caller_adjustment, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _number_of_frames, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _total_frame_sizes, int) \ + nonstatic_field(Deoptimization::UnrollBlock, _frame_sizes, intptr_t*) \ + nonstatic_field(Deoptimization::UnrollBlock, _frame_pcs, address*) \ + nonstatic_field(Deoptimization::UnrollBlock, _initial_info, intptr_t) \ + nonstatic_field(Deoptimization::UnrollBlock, _unpack_kind, int) \ + \ + nonstatic_field(ExceptionTableElement, start_pc, u2) \ + nonstatic_field(ExceptionTableElement, end_pc, u2) \ + nonstatic_field(ExceptionTableElement, handler_pc, u2) \ + nonstatic_field(ExceptionTableElement, catch_type_index, u2) \ + \ + nonstatic_field(Flag, _type, const char*) \ + nonstatic_field(Flag, _name, const char*) \ + unchecked_nonstatic_field(Flag, _addr, sizeof(void*)) \ + nonstatic_field(Flag, _flags, Flag::Flags) \ + static_field(Flag, flags, Flag*) \ + \ + nonstatic_field(InstanceKlass, _fields, Array*) \ + nonstatic_field(InstanceKlass, _constants, ConstantPool*) \ + nonstatic_field(InstanceKlass, _source_file_name_index, u2) \ + nonstatic_field(InstanceKlass, _init_state, u1) \ + \ + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_sp, intptr_t*) \ + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_pc, address) \ + \ + nonstatic_field(JavaThread, _threadObj, oop) \ + nonstatic_field(JavaThread, _anchor, JavaFrameAnchor) \ + nonstatic_field(JavaThread, _vm_result, oop) \ + volatile_nonstatic_field(JavaThread, _exception_oop, oop) \ + volatile_nonstatic_field(JavaThread, _exception_pc, address) \ + volatile_nonstatic_field(JavaThread, _is_method_handle_return, int) \ + nonstatic_field(JavaThread, _osthread, OSThread*) \ + nonstatic_field(JavaThread, _satb_mark_queue, SATBMarkQueue) \ + nonstatic_field(JavaThread, _dirty_card_queue, DirtyCardQueue) \ + nonstatic_field(JavaThread, _pending_deoptimization, int) \ + nonstatic_field(JavaThread, _pending_failed_speculation, oop) \ + nonstatic_field(JavaThread, _pending_transfer_to_interpreter, bool) \ + nonstatic_field(JavaThread, _jvmci_counters, jlong*) \ + \ + static_field(java_lang_Class, _klass_offset, int) \ + static_field(java_lang_Class, _array_klass_offset, int) \ + \ + nonstatic_field(JVMCIEnv, _task, CompileTask*) \ + nonstatic_field(JVMCIEnv, _jvmti_can_hotswap_or_post_breakpoint, bool) \ + \ + nonstatic_field(Klass, _secondary_super_cache, Klass*) \ + nonstatic_field(Klass, _secondary_supers, Array*) \ + nonstatic_field(Klass, _super, Klass*) \ + nonstatic_field(Klass, _super_check_offset, juint) \ + nonstatic_field(Klass, _subklass, Klass*) \ + nonstatic_field(Klass, _layout_helper, jint) \ + nonstatic_field(Klass, _prototype_header, markOop) \ + nonstatic_field(Klass, _next_sibling, Klass*) \ + nonstatic_field(Klass, _java_mirror, oop) \ + nonstatic_field(Klass, _modifier_flags, jint) \ + nonstatic_field(Klass, _access_flags, AccessFlags) \ + \ + nonstatic_field(LocalVariableTableElement, start_bci, u2) \ + nonstatic_field(LocalVariableTableElement, length, u2) \ + nonstatic_field(LocalVariableTableElement, name_cp_index, u2) \ + nonstatic_field(LocalVariableTableElement, descriptor_cp_index, u2) \ + nonstatic_field(LocalVariableTableElement, signature_cp_index, u2) \ + nonstatic_field(LocalVariableTableElement, slot, u2) \ + \ + nonstatic_field(Method, _constMethod, ConstMethod*) \ + nonstatic_field(Method, _method_data, MethodData*) \ + nonstatic_field(Method, _method_counters, MethodCounters*) \ + nonstatic_field(Method, _access_flags, AccessFlags) \ + nonstatic_field(Method, _vtable_index, int) \ + nonstatic_field(Method, _intrinsic_id, u2) \ + nonstatic_field(Method, _flags, u1) \ + volatile_nonstatic_field(Method, _code, nmethod*) \ + volatile_nonstatic_field(Method, _from_compiled_entry, address) \ + \ + nonstatic_field(MethodCounters, _invocation_counter, InvocationCounter) \ + nonstatic_field(MethodCounters, _backedge_counter, InvocationCounter) \ + \ + nonstatic_field(MethodData, _size, int) \ + nonstatic_field(MethodData, _data_size, int) \ + nonstatic_field(MethodData, _data[0], intptr_t) \ + nonstatic_field(MethodData, _trap_hist._array[0], u1) \ + nonstatic_field(MethodData, _jvmci_ir_size, int) \ + \ + nonstatic_field(nmethod, _verified_entry_point, address) \ + nonstatic_field(nmethod, _comp_level, int) \ + \ + nonstatic_field(ObjArrayKlass, _element_klass, Klass*) \ + \ + volatile_nonstatic_field(oopDesc, _mark, markOop) \ + volatile_nonstatic_field(oopDesc, _metadata._klass, Klass*) \ + \ + static_field(os, _polling_page, address) \ + \ + volatile_nonstatic_field(OSThread, _interrupted, jint) \ + \ + static_field(StubRoutines, _verify_oop_count, jint) \ + \ + static_field(StubRoutines, _jbyte_arraycopy, address) \ + static_field(StubRoutines, _jshort_arraycopy, address) \ + static_field(StubRoutines, _jint_arraycopy, address) \ + static_field(StubRoutines, _jlong_arraycopy, address) \ + static_field(StubRoutines, _oop_arraycopy, address) \ + static_field(StubRoutines, _oop_arraycopy_uninit, address) \ + static_field(StubRoutines, _jbyte_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jshort_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jint_disjoint_arraycopy, address) \ + static_field(StubRoutines, _jlong_disjoint_arraycopy, address) \ + static_field(StubRoutines, _oop_disjoint_arraycopy, address) \ + static_field(StubRoutines, _oop_disjoint_arraycopy_uninit, address) \ + static_field(StubRoutines, _arrayof_jbyte_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jshort_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jlong_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_arraycopy_uninit, address) \ + static_field(StubRoutines, _arrayof_jbyte_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jshort_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jint_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_jlong_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_disjoint_arraycopy, address) \ + static_field(StubRoutines, _arrayof_oop_disjoint_arraycopy_uninit, address) \ + static_field(StubRoutines, _checkcast_arraycopy, address) \ + static_field(StubRoutines, _checkcast_arraycopy_uninit, address) \ + static_field(StubRoutines, _unsafe_arraycopy, address) \ + static_field(StubRoutines, _generic_arraycopy, address) \ + \ + static_field(StubRoutines, _aescrypt_encryptBlock, address) \ + static_field(StubRoutines, _aescrypt_decryptBlock, address) \ + static_field(StubRoutines, _cipherBlockChaining_encryptAESCrypt, address) \ + static_field(StubRoutines, _cipherBlockChaining_decryptAESCrypt, address) \ + static_field(StubRoutines, _updateBytesCRC32, address) \ + static_field(StubRoutines, _crc_table_adr, address) \ + \ + nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \ + nonstatic_field(Thread, _allocated_bytes, jlong) \ + \ + nonstatic_field(ThreadLocalAllocBuffer, _start, HeapWord*) \ + nonstatic_field(ThreadLocalAllocBuffer, _top, HeapWord*) \ + nonstatic_field(ThreadLocalAllocBuffer, _end, HeapWord*) \ + nonstatic_field(ThreadLocalAllocBuffer, _pf_top, HeapWord*) \ + nonstatic_field(ThreadLocalAllocBuffer, _desired_size, size_t) \ + nonstatic_field(ThreadLocalAllocBuffer, _refill_waste_limit, size_t) \ + nonstatic_field(ThreadLocalAllocBuffer, _number_of_refills, unsigned) \ + nonstatic_field(ThreadLocalAllocBuffer, _fast_refill_waste, unsigned) \ + nonstatic_field(ThreadLocalAllocBuffer, _slow_allocations, unsigned) \ + \ + nonstatic_field(ThreadShadow, _pending_exception, oop) \ + \ + static_field(vmSymbols, _symbols[0], Symbol*) \ + \ + nonstatic_field(vtableEntry, _method, Method*) \ + +#define VM_TYPES(declare_type, declare_toplevel_type, declare_integer_type, declare_unsigned_integer_type) \ + declare_integer_type(bool) \ + declare_unsigned_integer_type(size_t) \ + declare_integer_type(intx) \ + declare_unsigned_integer_type(uintx) \ + \ + declare_toplevel_type(BasicLock) \ + declare_toplevel_type(CompilerToVM) \ + declare_toplevel_type(ExceptionTableElement) \ + declare_toplevel_type(Flag) \ + declare_toplevel_type(Flag*) \ + declare_toplevel_type(JVMCIEnv) \ + declare_toplevel_type(LocalVariableTableElement) \ + declare_toplevel_type(narrowKlass) \ + declare_toplevel_type(Symbol*) \ + declare_toplevel_type(vtableEntry) \ + \ + declare_toplevel_type(oopDesc) \ + declare_type(arrayOopDesc, oopDesc) \ + \ + declare_toplevel_type(MetaspaceObj) \ + declare_type(Metadata, MetaspaceObj) \ + declare_type(Klass, Metadata) \ + declare_type(InstanceKlass, Klass) \ + declare_type(ConstantPool, Metadata) \ + +#define VM_INT_CONSTANTS(declare_constant, declare_constant_with_value, declare_preprocessor_constant) \ + declare_preprocessor_constant("ASSERT", DEBUG_ONLY(1) NOT_DEBUG(0)) \ + declare_preprocessor_constant("FIELDINFO_TAG_SIZE", FIELDINFO_TAG_SIZE) \ + declare_preprocessor_constant("STACK_BIAS", STACK_BIAS) \ + \ + declare_constant(CompLevel_full_optimization) \ + declare_constant(HeapWordSize) \ + declare_constant(InvocationEntryBci) \ + declare_constant(LogKlassAlignmentInBytes) \ + \ + declare_constant(JVM_ACC_WRITTEN_FLAGS) \ + declare_constant(JVM_ACC_MONITOR_MATCH) \ + declare_constant(JVM_ACC_HAS_MONITOR_BYTECODES) \ + declare_constant(JVM_ACC_HAS_FINALIZER) \ + declare_constant(JVM_ACC_FIELD_INTERNAL) \ + declare_constant(JVM_ACC_FIELD_STABLE) \ + declare_constant(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) \ + declare_preprocessor_constant("JVM_ACC_SYNTHETIC", JVM_ACC_SYNTHETIC) \ + declare_preprocessor_constant("JVM_RECOGNIZED_FIELD_MODIFIERS", JVM_RECOGNIZED_FIELD_MODIFIERS) \ + \ + declare_constant(JVM_CONSTANT_Utf8) \ + declare_constant(JVM_CONSTANT_Unicode) \ + declare_constant(JVM_CONSTANT_Integer) \ + declare_constant(JVM_CONSTANT_Float) \ + declare_constant(JVM_CONSTANT_Long) \ + declare_constant(JVM_CONSTANT_Double) \ + declare_constant(JVM_CONSTANT_Class) \ + declare_constant(JVM_CONSTANT_String) \ + declare_constant(JVM_CONSTANT_Fieldref) \ + declare_constant(JVM_CONSTANT_Methodref) \ + declare_constant(JVM_CONSTANT_InterfaceMethodref) \ + declare_constant(JVM_CONSTANT_NameAndType) \ + declare_constant(JVM_CONSTANT_MethodHandle) \ + declare_constant(JVM_CONSTANT_MethodType) \ + declare_constant(JVM_CONSTANT_InvokeDynamic) \ + declare_constant(JVM_CONSTANT_ExternalMax) \ + \ + declare_constant(JVM_CONSTANT_Invalid) \ + declare_constant(JVM_CONSTANT_InternalMin) \ + declare_constant(JVM_CONSTANT_UnresolvedClass) \ + declare_constant(JVM_CONSTANT_ClassIndex) \ + declare_constant(JVM_CONSTANT_StringIndex) \ + declare_constant(JVM_CONSTANT_UnresolvedClassInError) \ + declare_constant(JVM_CONSTANT_MethodHandleInError) \ + declare_constant(JVM_CONSTANT_MethodTypeInError) \ + declare_constant(JVM_CONSTANT_InternalMax) \ + \ + declare_constant(ArrayData::array_len_off_set) \ + declare_constant(ArrayData::array_start_off_set) \ + \ + declare_constant(BitData::exception_seen_flag) \ + declare_constant(BitData::null_seen_flag) \ + declare_constant(BranchData::not_taken_off_set) \ + \ + declare_constant_with_value("CardTableModRefBS::dirty_card", CardTableModRefBS::dirty_card_val()) \ + \ + declare_constant(CodeInstaller::VERIFIED_ENTRY) \ + declare_constant(CodeInstaller::UNVERIFIED_ENTRY) \ + declare_constant(CodeInstaller::OSR_ENTRY) \ + declare_constant(CodeInstaller::EXCEPTION_HANDLER_ENTRY) \ + declare_constant(CodeInstaller::DEOPT_HANDLER_ENTRY) \ + declare_constant(CodeInstaller::INVOKEINTERFACE) \ + declare_constant(CodeInstaller::INVOKEVIRTUAL) \ + declare_constant(CodeInstaller::INVOKESTATIC) \ + declare_constant(CodeInstaller::INVOKESPECIAL) \ + declare_constant(CodeInstaller::INLINE_INVOKE) \ + declare_constant(CodeInstaller::POLL_NEAR) \ + declare_constant(CodeInstaller::POLL_RETURN_NEAR) \ + declare_constant(CodeInstaller::POLL_FAR) \ + declare_constant(CodeInstaller::POLL_RETURN_FAR) \ + declare_constant(CodeInstaller::CARD_TABLE_SHIFT) \ + declare_constant(CodeInstaller::CARD_TABLE_ADDRESS) \ + declare_constant(CodeInstaller::HEAP_TOP_ADDRESS) \ + declare_constant(CodeInstaller::HEAP_END_ADDRESS) \ + declare_constant(CodeInstaller::NARROW_KLASS_BASE_ADDRESS) \ + declare_constant(CodeInstaller::CRC_TABLE_ADDRESS) \ + declare_constant(CodeInstaller::INVOKE_INVALID) \ + \ + declare_constant(ConstantPool::CPCACHE_INDEX_TAG) \ + \ + declare_constant(ConstMethod::_has_linenumber_table) \ + declare_constant(ConstMethod::_has_localvariable_table) \ + declare_constant(ConstMethod::_has_exception_table) \ + \ + declare_constant(CounterData::count_off) \ + \ + declare_constant(DataLayout::cell_size) \ + declare_constant(DataLayout::no_tag) \ + declare_constant(DataLayout::bit_data_tag) \ + declare_constant(DataLayout::counter_data_tag) \ + declare_constant(DataLayout::jump_data_tag) \ + declare_constant(DataLayout::receiver_type_data_tag) \ + declare_constant(DataLayout::virtual_call_data_tag) \ + declare_constant(DataLayout::ret_data_tag) \ + declare_constant(DataLayout::branch_data_tag) \ + declare_constant(DataLayout::multi_branch_data_tag) \ + declare_constant(DataLayout::arg_info_data_tag) \ + declare_constant(DataLayout::call_type_data_tag) \ + declare_constant(DataLayout::virtual_call_type_data_tag) \ + declare_constant(DataLayout::parameters_type_data_tag) \ + declare_constant(DataLayout::speculative_trap_data_tag) \ + \ + declare_constant(Deoptimization::Unpack_deopt) \ + declare_constant(Deoptimization::Unpack_exception) \ + declare_constant(Deoptimization::Unpack_uncommon_trap) \ + declare_constant(Deoptimization::Unpack_reexecute) \ + \ + declare_constant(Deoptimization::_action_bits) \ + declare_constant(Deoptimization::_reason_bits) \ + declare_constant(Deoptimization::_debug_id_bits) \ + declare_constant(Deoptimization::_action_shift) \ + declare_constant(Deoptimization::_reason_shift) \ + declare_constant(Deoptimization::_debug_id_shift) \ + \ + declare_constant(Deoptimization::Action_none) \ + declare_constant(Deoptimization::Action_maybe_recompile) \ + declare_constant(Deoptimization::Action_reinterpret) \ + declare_constant(Deoptimization::Action_make_not_entrant) \ + declare_constant(Deoptimization::Action_make_not_compilable) \ + \ + declare_constant(Deoptimization::Reason_none) \ + declare_constant(Deoptimization::Reason_null_check) \ + declare_constant(Deoptimization::Reason_range_check) \ + declare_constant(Deoptimization::Reason_class_check) \ + declare_constant(Deoptimization::Reason_array_check) \ + declare_constant(Deoptimization::Reason_unreached0) \ + declare_constant(Deoptimization::Reason_constraint) \ + declare_constant(Deoptimization::Reason_div0_check) \ + declare_constant(Deoptimization::Reason_loop_limit_check) \ + declare_constant(Deoptimization::Reason_type_checked_inlining) \ + declare_constant(Deoptimization::Reason_optimized_type_check) \ + declare_constant(Deoptimization::Reason_aliasing) \ + declare_constant(Deoptimization::Reason_transfer_to_interpreter) \ + declare_constant(Deoptimization::Reason_not_compiled_exception_handler) \ + declare_constant(Deoptimization::Reason_unresolved) \ + declare_constant(Deoptimization::Reason_jsr_mismatch) \ + declare_constant(Deoptimization::Reason_LIMIT) \ + \ + declare_constant_with_value("dirtyCardQueueBufferOffset", in_bytes(DirtyCardQueue::byte_offset_of_buf())) \ + declare_constant_with_value("dirtyCardQueueIndexOffset", in_bytes(DirtyCardQueue::byte_offset_of_index())) \ + \ + declare_constant(FieldInfo::access_flags_offset) \ + declare_constant(FieldInfo::name_index_offset) \ + declare_constant(FieldInfo::signature_index_offset) \ + declare_constant(FieldInfo::initval_index_offset) \ + declare_constant(FieldInfo::low_packed_offset) \ + declare_constant(FieldInfo::high_packed_offset) \ + declare_constant(FieldInfo::field_slots) \ + \ + declare_constant(InstanceKlass::linked) \ + declare_constant(InstanceKlass::fully_initialized) \ + \ + declare_constant(JumpData::taken_off_set) \ + declare_constant(JumpData::displacement_off_set) \ + \ + declare_constant(JVMCIEnv::ok) \ + declare_constant(JVMCIEnv::dependencies_failed) \ + declare_constant(JVMCIEnv::dependencies_invalid) \ + declare_constant(JVMCIEnv::cache_full) \ + declare_constant(JVMCIEnv::code_too_large) \ + \ + declare_constant(Klass::_lh_neutral_value) \ + declare_constant(Klass::_lh_instance_slow_path_bit) \ + declare_constant(Klass::_lh_log2_element_size_shift) \ + declare_constant(Klass::_lh_log2_element_size_mask) \ + declare_constant(Klass::_lh_element_type_shift) \ + declare_constant(Klass::_lh_element_type_mask) \ + declare_constant(Klass::_lh_header_size_shift) \ + declare_constant(Klass::_lh_header_size_mask) \ + declare_constant(Klass::_lh_array_tag_shift) \ + declare_constant(Klass::_lh_array_tag_type_value) \ + declare_constant(Klass::_lh_array_tag_obj_value) \ + \ + declare_constant(markOopDesc::no_hash) \ + \ + declare_constant(Method::_jfr_towrite) \ + declare_constant(Method::_caller_sensitive) \ + declare_constant(Method::_force_inline) \ + declare_constant(Method::_dont_inline) \ + declare_constant(Method::_hidden) \ + \ + declare_constant(Method::nonvirtual_vtable_index) \ + declare_constant(Method::invalid_vtable_index) \ + \ + declare_constant(MultiBranchData::per_case_cell_count) \ + \ + declare_constant(ReceiverTypeData::nonprofiled_count_off_set) \ + declare_constant(ReceiverTypeData::receiver_type_row_cell_count) \ + declare_constant(ReceiverTypeData::receiver0_offset) \ + declare_constant(ReceiverTypeData::count0_offset) \ + \ + declare_constant_with_value("satbMarkQueueBufferOffset", in_bytes(SATBMarkQueue::byte_offset_of_buf())) \ + declare_constant_with_value("satbMarkQueueIndexOffset", in_bytes(SATBMarkQueue::byte_offset_of_index())) \ + declare_constant_with_value("satbMarkQueueActiveOffset", in_bytes(SATBMarkQueue::byte_offset_of_active())) \ + \ + declare_constant(vmIntrinsics::_invokeBasic) \ + declare_constant(vmIntrinsics::_linkToVirtual) \ + declare_constant(vmIntrinsics::_linkToStatic) \ + declare_constant(vmIntrinsics::_linkToSpecial) \ + declare_constant(vmIntrinsics::_linkToInterface) \ + \ + declare_constant(vmSymbols::FIRST_SID) \ + declare_constant(vmSymbols::SID_LIMIT) \ + +#define VM_LONG_CONSTANTS(declare_constant, declare_preprocessor_constant) \ + declare_constant(InvocationCounter::count_increment) \ + declare_constant(InvocationCounter::count_shift) \ + \ + declare_constant(markOopDesc::hash_shift) \ + \ + declare_constant(markOopDesc::biased_lock_mask_in_place) \ + declare_constant(markOopDesc::age_mask_in_place) \ + declare_constant(markOopDesc::epoch_mask_in_place) \ + declare_constant(markOopDesc::hash_mask) \ + declare_constant(markOopDesc::hash_mask_in_place) \ + \ + declare_constant(markOopDesc::unlocked_value) \ + declare_constant(markOopDesc::biased_lock_pattern) \ + \ + declare_constant(markOopDesc::no_hash_in_place) \ + declare_constant(markOopDesc::no_lock_in_place) \ + +#define VM_ADDRESSES(declare_address, declare_preprocessor_address, declare_function) \ + declare_function(SharedRuntime::register_finalizer) \ + declare_function(SharedRuntime::exception_handler_for_return_address) \ + declare_function(SharedRuntime::OSR_migration_end) \ + declare_function(SharedRuntime::dsin) \ + declare_function(SharedRuntime::dcos) \ + declare_function(SharedRuntime::dtan) \ + declare_function(SharedRuntime::dexp) \ + declare_function(SharedRuntime::dlog) \ + declare_function(SharedRuntime::dlog10) \ + declare_function(SharedRuntime::dpow) \ + \ + declare_function(os::dll_load) \ + declare_function(os::dll_lookup) \ + declare_function(os::javaTimeMillis) \ + declare_function(os::javaTimeNanos) \ + \ + declare_function(Deoptimization::fetch_unroll_info) \ + COMPILER2_PRESENT(declare_function(Deoptimization::uncommon_trap)) \ + declare_function(Deoptimization::unpack_frames) \ + \ + declare_function(JVMCIRuntime::new_instance) \ + declare_function(JVMCIRuntime::new_array) \ + declare_function(JVMCIRuntime::new_multi_array) \ + declare_function(JVMCIRuntime::dynamic_new_array) \ + declare_function(JVMCIRuntime::dynamic_new_instance) \ + \ + declare_function(JVMCIRuntime::thread_is_interrupted) \ + declare_function(JVMCIRuntime::vm_message) \ + declare_function(JVMCIRuntime::identity_hash_code) \ + declare_function(JVMCIRuntime::exception_handler_for_pc) \ + declare_function(JVMCIRuntime::monitorenter) \ + declare_function(JVMCIRuntime::monitorexit) \ + declare_function(JVMCIRuntime::create_null_exception) \ + declare_function(JVMCIRuntime::create_out_of_bounds_exception) \ + declare_function(JVMCIRuntime::log_primitive) \ + declare_function(JVMCIRuntime::log_object) \ + declare_function(JVMCIRuntime::log_printf) \ + declare_function(JVMCIRuntime::vm_error) \ + declare_function(JVMCIRuntime::load_and_clear_exception) \ + declare_function(JVMCIRuntime::write_barrier_pre) \ + declare_function(JVMCIRuntime::write_barrier_post) \ + declare_function(JVMCIRuntime::validate_object) \ + \ + declare_function(JVMCIRuntime::test_deoptimize_call_int) + + +#if INCLUDE_ALL_GCS + +#define VM_STRUCTS_G1(nonstatic_field, static_field) \ + static_field(HeapRegion, LogOfHRGrainBytes, int) + +#define VM_INT_CONSTANTS_G1(declare_constant, declare_constant_with_value, declare_preprocessor_constant) \ + declare_constant_with_value("G1SATBCardTableModRefBS::g1_young_gen", G1SATBCardTableModRefBS::g1_young_card_val()) + +#endif // INCLUDE_ALL_GCS + + +#ifdef TARGET_OS_FAMILY_linux + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) \ + declare_preprocessor_address("RTLD_DEFAULT", RTLD_DEFAULT) + +#endif // TARGET_OS_FAMILY_linux + + +#ifdef TARGET_OS_FAMILY_bsd + +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) \ + declare_preprocessor_address("RTLD_DEFAULT", RTLD_DEFAULT) + +#endif // TARGET_OS_FAMILY_bsd + + +#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) \ + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) \ + static_field(VM_Version, _cpuFeatures, uint64_t) + +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + declare_toplevel_type(VM_Version) + +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ + LP64_ONLY(declare_constant(frame::arg_reg_save_area_bytes)) \ + declare_constant(frame::interpreter_frame_sender_sp_offset) \ + declare_constant(frame::interpreter_frame_last_sp_offset) \ + declare_constant(VM_Version::CPU_CX8) \ + declare_constant(VM_Version::CPU_CMOV) \ + declare_constant(VM_Version::CPU_FXSR) \ + declare_constant(VM_Version::CPU_HT) \ + declare_constant(VM_Version::CPU_MMX) \ + declare_constant(VM_Version::CPU_3DNOW_PREFETCH) \ + declare_constant(VM_Version::CPU_SSE) \ + declare_constant(VM_Version::CPU_SSE2) \ + declare_constant(VM_Version::CPU_SSE3) \ + declare_constant(VM_Version::CPU_SSSE3) \ + declare_constant(VM_Version::CPU_SSE4A) \ + declare_constant(VM_Version::CPU_SSE4_1) \ + declare_constant(VM_Version::CPU_SSE4_2) \ + declare_constant(VM_Version::CPU_POPCNT) \ + declare_constant(VM_Version::CPU_LZCNT) \ + declare_constant(VM_Version::CPU_TSC) \ + declare_constant(VM_Version::CPU_TSCINV) \ + declare_constant(VM_Version::CPU_AVX) \ + declare_constant(VM_Version::CPU_AVX2) \ + declare_constant(VM_Version::CPU_AES) \ + declare_constant(VM_Version::CPU_ERMS) \ + declare_constant(VM_Version::CPU_CLMUL) \ + declare_constant(VM_Version::CPU_BMI1) \ + declare_constant(VM_Version::CPU_BMI2) \ + declare_constant(VM_Version::CPU_RTM) \ + declare_constant(VM_Version::CPU_ADX) \ + declare_constant(VM_Version::CPU_AVX512F) \ + declare_constant(VM_Version::CPU_AVX512DQ) \ + declare_constant(VM_Version::CPU_AVX512PF) \ + declare_constant(VM_Version::CPU_AVX512ER) \ + declare_constant(VM_Version::CPU_AVX512CD) \ + declare_constant(VM_Version::CPU_AVX512BW) + +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \ + declare_preprocessor_constant("VM_Version::CPU_AVX512VL", CPU_AVX512VL) + +#endif // TARGET_ARCH_x86 + + +/* + * Dummy defines for architectures that don't use these. + */ +#ifndef VM_STRUCTS_CPU +#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) +#endif + +#ifndef VM_TYPES_CPU +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#endif + +#ifndef VM_INT_CONSTANTS_CPU +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#endif + +#ifndef VM_LONG_CONSTANTS_CPU +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#endif + +#ifndef VM_STRUCTS_OS +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) +#endif + +#ifndef VM_TYPES_OS +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#endif + +#ifndef VM_INT_CONSTANTS_OS +#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#endif + +#ifndef VM_LONG_CONSTANTS_OS +#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) +#endif + +#ifndef VM_ADDRESSES_OS +#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) +#endif + + +// whole purpose of this function is to work around bug c++/27724 in gcc 4.1.1 +// with optimization turned on it doesn't affect produced code +static inline uint64_t cast_uint64_t(size_t x) +{ + return x; +} + +#define ASSIGN_CONST_TO_64BIT_VAR(var, expr) \ + JNIEXPORT uint64_t var = cast_uint64_t(expr); + +#define ASSIGN_OFFSET_TO_64BIT_VAR(var, type, field) \ + ASSIGN_CONST_TO_64BIT_VAR(var, offset_of(type, field)) + +#define ASSIGN_STRIDE_TO_64BIT_VAR(var, array) \ + ASSIGN_CONST_TO_64BIT_VAR(var, (char*)&array[1] - (char*)&array[0]) + +// +// Instantiation of VMStructEntries, VMTypeEntries and VMIntConstantEntries +// + +// These initializers are allowed to access private fields in classes +// as long as class VMStructs is a friend +VMStructEntry JVMCIVMStructs::localHotSpotVMStructs[] = { + VM_STRUCTS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY, + GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONSTATIC_VM_STRUCT_ENTRY) + + VM_STRUCTS_OS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY, + GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, + GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + + VM_STRUCTS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY, + GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C2_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, + GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) + +#if INCLUDE_ALL_GCS + VM_STRUCTS_G1(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, + GENERATE_STATIC_VM_STRUCT_ENTRY) +#endif + + GENERATE_VM_STRUCT_LAST_ENTRY() +}; + +VMTypeEntry JVMCIVMStructs::localHotSpotVMTypes[] = { + VM_TYPES(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_INTEGER_VM_TYPE_ENTRY, + GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY) + + VM_TYPES_OS(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_OOP_VM_TYPE_ENTRY, + GENERATE_INTEGER_VM_TYPE_ENTRY, + GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, + GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_C2_VM_TYPE_ENTRY, + GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) + + VM_TYPES_CPU(GENERATE_VM_TYPE_ENTRY, + GENERATE_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_OOP_VM_TYPE_ENTRY, + GENERATE_INTEGER_VM_TYPE_ENTRY, + GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY, + GENERATE_C1_TOPLEVEL_VM_TYPE_ENTRY, + GENERATE_C2_VM_TYPE_ENTRY, + GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) + + GENERATE_VM_TYPE_LAST_ENTRY() +}; + +VMIntConstantEntry JVMCIVMStructs::localHotSpotVMIntConstants[] = { + VM_INT_CONSTANTS(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + + VM_INT_CONSTANTS_OS(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, + GENERATE_C1_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + + VM_INT_CONSTANTS_CPU(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY, + GENERATE_C1_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_VM_INT_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) + +#if INCLUDE_ALL_GCS + VM_INT_CONSTANTS_G1(GENERATE_VM_INT_CONSTANT_ENTRY, + GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY, + GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) +#endif + + GENERATE_VM_INT_CONSTANT_LAST_ENTRY() +}; + +VMLongConstantEntry JVMCIVMStructs::localHotSpotVMLongConstants[] = { + VM_LONG_CONSTANTS(GENERATE_VM_LONG_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + + VM_LONG_CONSTANTS_OS(GENERATE_VM_LONG_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, + GENERATE_C1_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + + VM_LONG_CONSTANTS_CPU(GENERATE_VM_LONG_CONSTANT_ENTRY, + GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY, + GENERATE_C1_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_VM_LONG_CONSTANT_ENTRY, + GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY) + + GENERATE_VM_LONG_CONSTANT_LAST_ENTRY() +}; + +VMAddressEntry JVMCIVMStructs::localHotSpotVMAddresses[] = { + VM_ADDRESSES(GENERATE_VM_ADDRESS_ENTRY, + GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, + GENERATE_VM_FUNCTION_ENTRY) + + VM_ADDRESSES_OS(GENERATE_VM_ADDRESS_ENTRY, + GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, + GENERATE_VM_FUNCTION_ENTRY) + + GENERATE_VM_ADDRESS_LAST_ENTRY() +}; + +extern "C" { +JNIEXPORT VMStructEntry* jvmciHotSpotVMStructs = JVMCIVMStructs::localHotSpotVMStructs; +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMStructEntryTypeNameOffset, VMStructEntry, typeName); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMStructEntryFieldNameOffset, VMStructEntry, fieldName); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMStructEntryTypeStringOffset, VMStructEntry, typeString); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMStructEntryIsStaticOffset, VMStructEntry, isStatic); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMStructEntryOffsetOffset, VMStructEntry, offset); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMStructEntryAddressOffset, VMStructEntry, address); +ASSIGN_STRIDE_TO_64BIT_VAR(jvmciHotSpotVMStructEntryArrayStride, jvmciHotSpotVMStructs); + +JNIEXPORT VMTypeEntry* jvmciHotSpotVMTypes = JVMCIVMStructs::localHotSpotVMTypes; +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMTypeEntryTypeNameOffset, VMTypeEntry, typeName); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMTypeEntrySuperclassNameOffset, VMTypeEntry, superclassName); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMTypeEntryIsOopTypeOffset, VMTypeEntry, isOopType); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMTypeEntryIsIntegerTypeOffset, VMTypeEntry, isIntegerType); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMTypeEntryIsUnsignedOffset, VMTypeEntry, isUnsigned); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMTypeEntrySizeOffset, VMTypeEntry, size); +ASSIGN_STRIDE_TO_64BIT_VAR(jvmciHotSpotVMTypeEntryArrayStride, jvmciHotSpotVMTypes); + +JNIEXPORT VMIntConstantEntry* jvmciHotSpotVMIntConstants = JVMCIVMStructs::localHotSpotVMIntConstants; +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMIntConstantEntryNameOffset, VMIntConstantEntry, name); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMIntConstantEntryValueOffset, VMIntConstantEntry, value); +ASSIGN_STRIDE_TO_64BIT_VAR(jvmciHotSpotVMIntConstantEntryArrayStride, jvmciHotSpotVMIntConstants); + +JNIEXPORT VMLongConstantEntry* jvmciHotSpotVMLongConstants = JVMCIVMStructs::localHotSpotVMLongConstants; +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMLongConstantEntryNameOffset, VMLongConstantEntry, name); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMLongConstantEntryValueOffset, VMLongConstantEntry, value); +ASSIGN_STRIDE_TO_64BIT_VAR(jvmciHotSpotVMLongConstantEntryArrayStride, jvmciHotSpotVMLongConstants); + +JNIEXPORT VMAddressEntry* jvmciHotSpotVMAddresses = JVMCIVMStructs::localHotSpotVMAddresses; +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMAddressEntryNameOffset, VMAddressEntry, name); +ASSIGN_OFFSET_TO_64BIT_VAR(jvmciHotSpotVMAddressEntryValueOffset, VMAddressEntry, value); +ASSIGN_STRIDE_TO_64BIT_VAR(jvmciHotSpotVMAddressEntryArrayStride, jvmciHotSpotVMAddresses); +} diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.hpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.hpp index a58a6ef74c7..36bfe7289c9 100644 --- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.hpp +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.hpp @@ -25,113 +25,36 @@ #ifndef SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP #define SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP -#include "compiler/abstractCompiler.hpp" -#include "jvmci/jvmciCodeInstaller.hpp" -#include "jvmci/jvmciCompilerToVM.hpp" -#include "jvmci/jvmciEnv.hpp" -#include "jvmci/jvmciRuntime.hpp" +#include "runtime/vmStructs.hpp" -#define VM_STRUCTS_JVMCI(nonstatic_field, static_field) \ - nonstatic_field(JavaThread, _pending_deoptimization, int) \ - nonstatic_field(JavaThread, _pending_failed_speculation, oop) \ - nonstatic_field(JavaThread, _pending_transfer_to_interpreter, bool) \ - nonstatic_field(JavaThread, _jvmci_counters, jlong*) \ - nonstatic_field(MethodData, _jvmci_ir_size, int) \ - nonstatic_field(JVMCIEnv, _task, CompileTask*) \ - nonstatic_field(JVMCIEnv, _jvmti_can_hotswap_or_post_breakpoint, bool) \ - nonstatic_field(DeoptimizationBlob, _uncommon_trap_offset, int) \ - \ - static_field(CompilerToVM, _supports_inline_contig_alloc, bool) \ - static_field(CompilerToVM, _heap_end_addr, HeapWord**) \ - static_field(CompilerToVM, _heap_top_addr, HeapWord**) +class JVMCIVMStructs { +public: + /** + * The last entry has a NULL fieldName. + */ + static VMStructEntry localHotSpotVMStructs[]; -#define VM_TYPES_JVMCI(declare_type, declare_toplevel_type) \ - declare_toplevel_type(CompilerToVM) \ - declare_toplevel_type(JVMCIEnv) \ + /** + * The last entry has a NULL typeName. + */ + static VMTypeEntry localHotSpotVMTypes[]; -#define VM_INT_CONSTANTS_JVMCI(declare_constant, declare_preprocessor_constant) \ - declare_constant(Deoptimization::Reason_unreached0) \ - declare_constant(Deoptimization::Reason_type_checked_inlining) \ - declare_constant(Deoptimization::Reason_optimized_type_check) \ - declare_constant(Deoptimization::Reason_aliasing) \ - declare_constant(Deoptimization::Reason_transfer_to_interpreter) \ - declare_constant(Deoptimization::Reason_not_compiled_exception_handler) \ - declare_constant(Deoptimization::Reason_unresolved) \ - declare_constant(Deoptimization::Reason_jsr_mismatch) \ - declare_constant(JVMCIEnv::ok) \ - declare_constant(JVMCIEnv::dependencies_failed) \ - declare_constant(JVMCIEnv::dependencies_invalid) \ - declare_constant(JVMCIEnv::cache_full) \ - declare_constant(JVMCIEnv::code_too_large) \ - \ - declare_preprocessor_constant("JVM_ACC_SYNTHETIC", JVM_ACC_SYNTHETIC) \ - declare_preprocessor_constant("JVM_RECOGNIZED_FIELD_MODIFIERS", JVM_RECOGNIZED_FIELD_MODIFIERS) \ - \ - declare_constant(CompilerToVM::KLASS_TAG) \ - declare_constant(CompilerToVM::SYMBOL_TAG) \ - \ - declare_constant(BitData::exception_seen_flag) \ - declare_constant(BitData::null_seen_flag) \ - declare_constant(CounterData::count_off) \ - declare_constant(JumpData::taken_off_set) \ - declare_constant(JumpData::displacement_off_set) \ - declare_constant(ReceiverTypeData::nonprofiled_count_off_set) \ - declare_constant(ReceiverTypeData::receiver_type_row_cell_count) \ - declare_constant(ReceiverTypeData::receiver0_offset) \ - declare_constant(ReceiverTypeData::count0_offset) \ - declare_constant(BranchData::not_taken_off_set) \ - declare_constant(ArrayData::array_len_off_set) \ - declare_constant(ArrayData::array_start_off_set) \ - declare_constant(MultiBranchData::per_case_cell_count) \ - \ - declare_constant(CodeInstaller::VERIFIED_ENTRY) \ - declare_constant(CodeInstaller::UNVERIFIED_ENTRY) \ - declare_constant(CodeInstaller::OSR_ENTRY) \ - declare_constant(CodeInstaller::EXCEPTION_HANDLER_ENTRY) \ - declare_constant(CodeInstaller::DEOPT_HANDLER_ENTRY) \ - declare_constant(CodeInstaller::INVOKEINTERFACE) \ - declare_constant(CodeInstaller::INVOKEVIRTUAL) \ - declare_constant(CodeInstaller::INVOKESTATIC) \ - declare_constant(CodeInstaller::INVOKESPECIAL) \ - declare_constant(CodeInstaller::INLINE_INVOKE) \ - declare_constant(CodeInstaller::POLL_NEAR) \ - declare_constant(CodeInstaller::POLL_RETURN_NEAR) \ - declare_constant(CodeInstaller::POLL_FAR) \ - declare_constant(CodeInstaller::POLL_RETURN_FAR) \ - declare_constant(CodeInstaller::CARD_TABLE_SHIFT) \ - declare_constant(CodeInstaller::CARD_TABLE_ADDRESS) \ - declare_constant(CodeInstaller::HEAP_TOP_ADDRESS) \ - declare_constant(CodeInstaller::HEAP_END_ADDRESS) \ - declare_constant(CodeInstaller::NARROW_KLASS_BASE_ADDRESS) \ - declare_constant(CodeInstaller::CRC_TABLE_ADDRESS) \ - declare_constant(CodeInstaller::INVOKE_INVALID) \ - \ - declare_constant(Method::invalid_vtable_index) \ + /** + * Table of integer constants. + * The last entry has a NULL typeName. + */ + static VMIntConstantEntry localHotSpotVMIntConstants[]; -#define VM_ADDRESSES_JVMCI(declare_address, declare_preprocessor_address, declare_function) \ - declare_function(JVMCIRuntime::new_instance) \ - declare_function(JVMCIRuntime::new_array) \ - declare_function(JVMCIRuntime::new_multi_array) \ - declare_function(JVMCIRuntime::dynamic_new_array) \ - declare_function(JVMCIRuntime::dynamic_new_instance) \ - \ - declare_function(JVMCIRuntime::thread_is_interrupted) \ - declare_function(JVMCIRuntime::vm_message) \ - declare_function(JVMCIRuntime::identity_hash_code) \ - declare_function(JVMCIRuntime::exception_handler_for_pc) \ - declare_function(JVMCIRuntime::monitorenter) \ - declare_function(JVMCIRuntime::monitorexit) \ - declare_function(JVMCIRuntime::create_null_exception) \ - declare_function(JVMCIRuntime::create_out_of_bounds_exception) \ - declare_function(JVMCIRuntime::log_primitive) \ - declare_function(JVMCIRuntime::log_object) \ - declare_function(JVMCIRuntime::log_printf) \ - declare_function(JVMCIRuntime::vm_error) \ - declare_function(JVMCIRuntime::load_and_clear_exception) \ - declare_function(JVMCIRuntime::write_barrier_pre) \ - declare_function(JVMCIRuntime::write_barrier_post) \ - declare_function(JVMCIRuntime::validate_object) \ - \ - declare_function(JVMCIRuntime::test_deoptimize_call_int) + /** + * Table of long constants. + * The last entry has a NULL typeName. + */ + static VMLongConstantEntry localHotSpotVMLongConstants[]; + + /** + * Table of addresses. + */ + static VMAddressEntry localHotSpotVMAddresses[]; +}; #endif // SHARE_VM_JVMCI_VMSTRUCTS_JVMCI_HPP diff --git a/hotspot/src/share/vm/oops/constMethod.hpp b/hotspot/src/share/vm/oops/constMethod.hpp index b5360571cdb..5bd135ebf17 100644 --- a/hotspot/src/share/vm/oops/constMethod.hpp +++ b/hotspot/src/share/vm/oops/constMethod.hpp @@ -166,9 +166,9 @@ class InlineTableSizes : StackObj { #undef INLINE_TABLE_PARAM #undef INLINE_TABLE_DECLARE - class ConstMethod : public MetaspaceObj { friend class VMStructs; + friend class JVMCIVMStructs; public: typedef enum { NORMAL, OVERPASS } MethodType; diff --git a/hotspot/src/share/vm/oops/constantPool.hpp b/hotspot/src/share/vm/oops/constantPool.hpp index 99d77253be9..bbb099b22cb 100644 --- a/hotspot/src/share/vm/oops/constantPool.hpp +++ b/hotspot/src/share/vm/oops/constantPool.hpp @@ -74,6 +74,7 @@ class KlassSizeStats; class ConstantPool : public Metadata { friend class VMStructs; + friend class JVMCIVMStructs; friend class BytecodeInterpreter; // Directly extracts a klass in the pool for fast instanceof/checkcast friend class Universe; // For null constructor private: diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index ca5262346a1..0d2dac711e4 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -108,6 +108,7 @@ struct JvmtiCachedClassFileData; class InstanceKlass: public Klass { friend class VMStructs; + friend class JVMCIVMStructs; friend class ClassFileParser; friend class CompileReplay; diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index a7ddf019063..bfad79f5bb5 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -60,6 +60,7 @@ class fieldDescriptor; class Klass : public Metadata { friend class VMStructs; + friend class JVMCIVMStructs; protected: // note: put frequently-used fields together at start of klass structure // for better cache behavior (may not make much of a difference but sure won't hurt) diff --git a/hotspot/src/share/vm/oops/klassVtable.hpp b/hotspot/src/share/vm/oops/klassVtable.hpp index e4b4c9f5141..78a7bb39b1a 100644 --- a/hotspot/src/share/vm/oops/klassVtable.hpp +++ b/hotspot/src/share/vm/oops/klassVtable.hpp @@ -155,6 +155,7 @@ class klassVtable : public ResourceObj { // from_interpreter_entry_point -> i2cadapter class vtableEntry VALUE_OBJ_CLASS_SPEC { friend class VMStructs; + friend class JVMCIVMStructs; public: // size in words diff --git a/hotspot/src/share/vm/oops/method.hpp b/hotspot/src/share/vm/oops/method.hpp index 2b7bd268f5c..861b407c6cf 100644 --- a/hotspot/src/share/vm/oops/method.hpp +++ b/hotspot/src/share/vm/oops/method.hpp @@ -61,6 +61,7 @@ class KlassSizeStats; class Method : public Metadata { friend class VMStructs; + friend class JVMCIVMStructs; private: ConstMethod* _constMethod; // Method read-only data. MethodData* _method_data; diff --git a/hotspot/src/share/vm/oops/methodCounters.hpp b/hotspot/src/share/vm/oops/methodCounters.hpp index 039271b1c10..b52bff3104a 100644 --- a/hotspot/src/share/vm/oops/methodCounters.hpp +++ b/hotspot/src/share/vm/oops/methodCounters.hpp @@ -32,6 +32,7 @@ class MethodCounters: public MetaspaceObj { friend class VMStructs; + friend class JVMCIVMStructs; private: int _interpreter_invocation_count; // Count of times invoked (reused as prev_event_count in tiered) u2 _interpreter_throwout_count; // Count of times method was exited via exception while interpreting diff --git a/hotspot/src/share/vm/oops/methodData.hpp b/hotspot/src/share/vm/oops/methodData.hpp index 14afeccea57..c8d3d8fc247 100644 --- a/hotspot/src/share/vm/oops/methodData.hpp +++ b/hotspot/src/share/vm/oops/methodData.hpp @@ -73,6 +73,7 @@ class ProfileData; // Overlay for generic profiling data. class DataLayout VALUE_OBJ_CLASS_SPEC { friend class VMStructs; + friend class JVMCIVMStructs; private: // Every data layout begins with a header. This header @@ -536,6 +537,7 @@ public: // A BitData holds a flag or two in its header. class BitData : public ProfileData { friend class VMStructs; + friend class JVMCIVMStructs; protected: enum { // null_seen: @@ -605,6 +607,7 @@ public: // A CounterData corresponds to a simple counter. class CounterData : public BitData { friend class VMStructs; + friend class JVMCIVMStructs; protected: enum { count_off, @@ -670,6 +673,7 @@ public: // the corresponding target bci. class JumpData : public ProfileData { friend class VMStructs; + friend class JVMCIVMStructs; protected: enum { taken_off_set, @@ -1177,6 +1181,7 @@ public: // which are used to store a type profile for the receiver of the check. class ReceiverTypeData : public CounterData { friend class VMStructs; + friend class JVMCIVMStructs; protected: enum { #if INCLUDE_JVMCI @@ -1683,6 +1688,7 @@ public: // for the taken case. class BranchData : public JumpData { friend class VMStructs; + friend class JVMCIVMStructs; protected: enum { not_taken_off_set = jump_cell_count, @@ -1760,6 +1766,7 @@ public: // and an array start. class ArrayData : public ProfileData { friend class VMStructs; + friend class JVMCIVMStructs; protected: friend class DataLayout; @@ -1838,6 +1845,7 @@ public: // case was taken and specify the data displacment for each branch target. class MultiBranchData : public ArrayData { friend class VMStructs; + friend class JVMCIVMStructs; protected: enum { default_count_off_set, @@ -2137,6 +2145,7 @@ class CleanExtraDataClosure; class MethodData : public Metadata { friend class VMStructs; + friend class JVMCIVMStructs; CC_INTERP_ONLY(friend class BytecodeInterpreter;) private: friend class ProfileData; diff --git a/hotspot/src/share/vm/oops/objArrayKlass.hpp b/hotspot/src/share/vm/oops/objArrayKlass.hpp index d888fb7228a..560f266bc63 100644 --- a/hotspot/src/share/vm/oops/objArrayKlass.hpp +++ b/hotspot/src/share/vm/oops/objArrayKlass.hpp @@ -33,6 +33,7 @@ class ObjArrayKlass : public ArrayKlass { friend class VMStructs; + friend class JVMCIVMStructs; private: Klass* _element_klass; // The klass of the elements of this array type Klass* _bottom_klass; // The one-dimensional type (InstanceKlass or TypeArrayKlass) diff --git a/hotspot/src/share/vm/oops/oop.hpp b/hotspot/src/share/vm/oops/oop.hpp index b096f3f45c5..b7fa4c2de6e 100644 --- a/hotspot/src/share/vm/oops/oop.hpp +++ b/hotspot/src/share/vm/oops/oop.hpp @@ -58,6 +58,7 @@ class ParCompactionManager; class oopDesc { friend class VMStructs; + friend class JVMCIVMStructs; private: volatile markOop _mark; union _metadata { diff --git a/hotspot/src/share/vm/runtime/basicLock.hpp b/hotspot/src/share/vm/runtime/basicLock.hpp index 309e07c0bd0..cc4e37eed52 100644 --- a/hotspot/src/share/vm/runtime/basicLock.hpp +++ b/hotspot/src/share/vm/runtime/basicLock.hpp @@ -31,6 +31,7 @@ class BasicLock VALUE_OBJ_CLASS_SPEC { friend class VMStructs; + friend class JVMCIVMStructs; private: volatile markOop _displaced_header; public: diff --git a/hotspot/src/share/vm/runtime/deoptimization.hpp b/hotspot/src/share/vm/runtime/deoptimization.hpp index 7e63ab6bd38..82bb20af4e9 100644 --- a/hotspot/src/share/vm/runtime/deoptimization.hpp +++ b/hotspot/src/share/vm/runtime/deoptimization.hpp @@ -168,6 +168,7 @@ JVMCI_ONLY(public:) // This is only a CheapObj to ease debugging after a deopt failure class UnrollBlock : public CHeapObj { friend class VMStructs; + friend class JVMCIVMStructs; private: int _size_of_deoptimized_frame; // Size, in bytes, of current deoptimized frame int _caller_adjustment; // Adjustment, in bytes, to caller's SP by initial interpreted frame diff --git a/hotspot/src/share/vm/runtime/javaFrameAnchor.hpp b/hotspot/src/share/vm/runtime/javaFrameAnchor.hpp index fa3c279e001..efb4d415aa4 100644 --- a/hotspot/src/share/vm/runtime/javaFrameAnchor.hpp +++ b/hotspot/src/share/vm/runtime/javaFrameAnchor.hpp @@ -48,6 +48,7 @@ friend class StubGenerator; friend class JavaThread; friend class frame; friend class VMStructs; +friend class JVMCIVMStructs; friend class BytecodeInterpreter; friend class JavaCallWrapper; diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index 0e104226501..f4995159bcb 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -102,6 +102,7 @@ class MallocTracker; class os: AllStatic { friend class VMStructs; + friend class JVMCIVMStructs; friend class MallocTracker; public: enum { page_sizes_max = 9 }; // Size of _page_sizes array (8 plus a sentinel) diff --git a/hotspot/src/share/vm/runtime/osThread.hpp b/hotspot/src/share/vm/runtime/osThread.hpp index 02f3c0203fd..29912bd5187 100644 --- a/hotspot/src/share/vm/runtime/osThread.hpp +++ b/hotspot/src/share/vm/runtime/osThread.hpp @@ -60,6 +60,7 @@ enum ThreadState { class OSThread: public CHeapObj { friend class VMStructs; + friend class JVMCIVMStructs; private: OSThreadStartFunc _start_proc; // Thread start routine void* _start_parm; // Thread start routine parameter diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index 27c81f00346..de23fe565bd 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -101,6 +101,7 @@ class WorkerThread; class Thread: public ThreadShadow { friend class VMStructs; + friend class JVMCIVMStructs; private: // Exception handling // (Note: _pending_exception and friends are in ThreadShadow) @@ -775,6 +776,7 @@ typedef void (*ThreadFunction)(JavaThread*, TRAPS); class JavaThread: public Thread { friend class VMStructs; + friend class JVMCIVMStructs; friend class WhiteBox; private: JavaThread* _next; // The next thread in the Threads list diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index d3e1b44de02..edeb34ed0f6 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -2844,104 +2844,6 @@ typedef CompactHashtable SymbolCompactHashTable; //-------------------------------------------------------------------------------- -// VM_ADDRESSES -// - -#define VM_ADDRESSES(declare_address, declare_preprocessor_address, declare_function) \ - \ - declare_function(SharedRuntime::register_finalizer) \ - declare_function(SharedRuntime::exception_handler_for_return_address) \ - declare_function(SharedRuntime::OSR_migration_end) \ - declare_function(SharedRuntime::dsin) \ - declare_function(SharedRuntime::dcos) \ - declare_function(SharedRuntime::dtan) \ - declare_function(SharedRuntime::dexp) \ - declare_function(SharedRuntime::dlog) \ - declare_function(SharedRuntime::dlog10) \ - declare_function(SharedRuntime::dpow) \ - \ - declare_function(os::dll_load) \ - declare_function(os::dll_lookup) \ - declare_function(os::javaTimeMillis) \ - declare_function(os::javaTimeNanos) \ - \ - declare_function(Deoptimization::fetch_unroll_info) \ - COMPILER2_PRESENT(declare_function(Deoptimization::uncommon_trap)) \ - declare_function(Deoptimization::unpack_frames) - -//-------------------------------------------------------------------------------- -// Macros operating on the above lists -//-------------------------------------------------------------------------------- - -// This utility macro quotes the passed string -#define QUOTE(x) #x - -//-------------------------------------------------------------------------------- -// VMStructEntry macros -// - -// This macro generates a VMStructEntry line for a nonstatic field -#define GENERATE_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - { QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 0, offset_of(typeName, fieldName), NULL }, - -// This macro generates a VMStructEntry line for a static field -#define GENERATE_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - { QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 1, 0, &typeName::fieldName }, - -// This macro generates a VMStructEntry line for a static pointer volatile field, -// e.g.: "static ObjectMonitor * volatile gBlockList;" -#define GENERATE_STATIC_PTR_VOLATILE_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - { QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 1, 0, (void *)&typeName::fieldName }, - -// This macro generates a VMStructEntry line for an unchecked -// nonstatic field, in which the size of the type is also specified. -// The type string is given as NULL, indicating an "opaque" type. -#define GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, size) \ - { QUOTE(typeName), QUOTE(fieldName), NULL, 0, offset_of(typeName, fieldName), NULL }, - -// This macro generates a VMStructEntry line for an unchecked -// static field, in which the size of the type is also specified. -// The type string is given as NULL, indicating an "opaque" type. -#define GENERATE_UNCHECKED_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, size) \ - { QUOTE(typeName), QUOTE(fieldName), NULL, 1, 0, (void*) &typeName::fieldName }, - -// This macro generates the sentinel value indicating the end of the list -#define GENERATE_VM_STRUCT_LAST_ENTRY() \ - { NULL, NULL, NULL, 0, 0, NULL } - -// This macro checks the type of a VMStructEntry by comparing pointer types -#define CHECK_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - {typeName *dummyObj = NULL; type* dummy = &dummyObj->fieldName; \ - assert(offset_of(typeName, fieldName) < sizeof(typeName), "Illegal nonstatic struct entry, field offset too large"); } - -// This macro checks the type of a volatile VMStructEntry by comparing pointer types -#define CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - {typedef type dummyvtype; typeName *dummyObj = NULL; volatile dummyvtype* dummy = &dummyObj->fieldName; } - -// This macro checks the type of a static VMStructEntry by comparing pointer types -#define CHECK_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - {type* dummy = &typeName::fieldName; } - -// This macro checks the type of a static pointer volatile VMStructEntry by comparing pointer types, -// e.g.: "static ObjectMonitor * volatile gBlockList;" -#define CHECK_STATIC_PTR_VOLATILE_VM_STRUCT_ENTRY(typeName, fieldName, type) \ - {type volatile * dummy = &typeName::fieldName; } - -// This macro ensures the type of a field and its containing type are -// present in the type table. The assertion string is shorter than -// preferable because (incredibly) of a bug in Solstice NFS client -// which seems to prevent very long lines from compiling. This assertion -// means that an entry in VMStructs::localHotSpotVMStructs[] was not -// found in VMStructs::localHotSpotVMTypes[]. -#define ENSURE_FIELD_TYPE_PRESENT(typeName, fieldName, type) \ - { assert(findType(QUOTE(typeName)) != 0, "type \"" QUOTE(typeName) "\" not found in type table"); \ - assert(findType(QUOTE(type)) != 0, "type \"" QUOTE(type) "\" not found in type table"); } - -// This is a no-op macro for unchecked fields -#define CHECK_NO_OP(a, b, c) - -// -// Build-specific macros: // // Generate and check a nonstatic field in non-product builds @@ -2997,35 +2899,7 @@ typedef CompactHashtable SymbolCompactHashTable; #endif /* COMPILER2 */ //-------------------------------------------------------------------------------- -// VMTypeEntry macros -// - -#define GENERATE_VM_TYPE_ENTRY(type, superclass) \ - { QUOTE(type), QUOTE(superclass), 0, 0, 0, sizeof(type) }, - -#define GENERATE_TOPLEVEL_VM_TYPE_ENTRY(type) \ - { QUOTE(type), NULL, 0, 0, 0, sizeof(type) }, - -#define GENERATE_OOP_VM_TYPE_ENTRY(type) \ - { QUOTE(type), NULL, 1, 0, 0, sizeof(type) }, - -#define GENERATE_INTEGER_VM_TYPE_ENTRY(type) \ - { QUOTE(type), NULL, 0, 1, 0, sizeof(type) }, - -#define GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY(type) \ - { QUOTE(type), NULL, 0, 1, 1, sizeof(type) }, - -#define GENERATE_VM_TYPE_LAST_ENTRY() \ - { NULL, NULL, 0, 0, 0, 0 } - -#define CHECK_VM_TYPE_ENTRY(type, superclass) \ - { type* dummyObj = NULL; superclass* dummySuperObj = dummyObj; } - -#define CHECK_VM_TYPE_NO_OP(a) -#define CHECK_SINGLE_ARG_VM_TYPE_NO_OP(a) - -// -// Build-specific macros: +// VMTypeEntry build-specific macros // #ifdef COMPILER1 @@ -3050,23 +2924,9 @@ typedef CompactHashtable SymbolCompactHashTable; //-------------------------------------------------------------------------------- -// VMIntConstantEntry macros +// VMIntConstantEntry build-specific macros // -#define GENERATE_VM_INT_CONSTANT_ENTRY(name) \ - { QUOTE(name), (int32_t) name }, - -#define GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY(name, value) \ - { (name), (int32_t)(value) }, - -#define GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY(name, value) \ - { name, (int32_t) value }, - -// This macro generates the sentinel value indicating the end of the list -#define GENERATE_VM_INT_CONSTANT_LAST_ENTRY() \ - { NULL, 0 } - - // Generate an int constant for a C1 build #ifdef COMPILER1 # define GENERATE_C1_VM_INT_CONSTANT_ENTRY(name) GENERATE_VM_INT_CONSTANT_ENTRY(name) @@ -3083,20 +2943,11 @@ typedef CompactHashtable SymbolCompactHashTable; # define GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY(name, value) #endif /* COMPILER1 */ + //-------------------------------------------------------------------------------- -// VMLongConstantEntry macros +// VMLongConstantEntry build-specific macros // -#define GENERATE_VM_LONG_CONSTANT_ENTRY(name) \ - { QUOTE(name), name }, - -#define GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY(name, value) \ - { name, value }, - -// This macro generates the sentinel value indicating the end of the list -#define GENERATE_VM_LONG_CONSTANT_LAST_ENTRY() \ - { NULL, 0 } - // Generate a long constant for a C1 build #ifdef COMPILER1 # define GENERATE_C1_VM_LONG_CONSTANT_ENTRY(name) GENERATE_VM_LONG_CONSTANT_ENTRY(name) @@ -3113,22 +2964,6 @@ typedef CompactHashtable SymbolCompactHashTable; # define GENERATE_C2_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY(name, value) #endif /* COMPILER1 */ -//-------------------------------------------------------------------------------- -// VMAddressEntry macros -// - -#define GENERATE_VM_ADDRESS_ENTRY(name) \ - { QUOTE(name), (void*) (name) }, - -#define GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY(name, value) \ - { name, (void*) (value) }, - -#define GENERATE_VM_FUNCTION_ENTRY(name) \ - { QUOTE(name), CAST_FROM_FN_PTR(void*, &(name)) }, - -// This macro generates the sentinel value indicating the end of the list -#define GENERATE_VM_ADDRESS_LAST_ENTRY() \ - { NULL, NULL } // // Instantiation of VMStructEntries, VMTypeEntries and VMIntConstantEntries @@ -3149,11 +2984,6 @@ VMStructEntry VMStructs::localHotSpotVMStructs[] = { GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY, GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY) -#if INCLUDE_JVMCI - VM_STRUCTS_JVMCI(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, - GENERATE_STATIC_VM_STRUCT_ENTRY) -#endif - #if INCLUDE_ALL_GCS VM_STRUCTS_PARALLELGC(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY) @@ -3215,11 +3045,6 @@ VMTypeEntry VMStructs::localHotSpotVMTypes[] = { GENERATE_C2_VM_TYPE_ENTRY, GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY) -#if INCLUDE_JVMCI - VM_TYPES_JVMCI(GENERATE_VM_TYPE_ENTRY, - GENERATE_TOPLEVEL_VM_TYPE_ENTRY) -#endif - #if INCLUDE_ALL_GCS VM_TYPES_PARALLELGC(GENERATE_VM_TYPE_ENTRY, GENERATE_TOPLEVEL_VM_TYPE_ENTRY) @@ -3279,12 +3104,6 @@ VMIntConstantEntry VMStructs::localHotSpotVMIntConstants[] = { GENERATE_C2_VM_INT_CONSTANT_ENTRY, GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) -#if INCLUDE_JVMCI - VM_INT_CONSTANTS_JVMCI(GENERATE_VM_INT_CONSTANT_ENTRY, - GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY) - -#endif - #if INCLUDE_ALL_GCS VM_INT_CONSTANTS_CMS(GENERATE_VM_INT_CONSTANT_ENTRY) @@ -3348,25 +3167,6 @@ VMLongConstantEntry VMStructs::localHotSpotVMLongConstants[] = { GENERATE_VM_LONG_CONSTANT_LAST_ENTRY() }; -VMAddressEntry VMStructs::localHotSpotVMAddresses[] = { - - VM_ADDRESSES(GENERATE_VM_ADDRESS_ENTRY, - GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, - GENERATE_VM_FUNCTION_ENTRY) - - VM_ADDRESSES_OS(GENERATE_VM_ADDRESS_ENTRY, - GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, - GENERATE_VM_FUNCTION_ENTRY) - -#if INCLUDE_JVMCI - VM_ADDRESSES_JVMCI(GENERATE_VM_ADDRESS_ENTRY, - GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY, - GENERATE_VM_FUNCTION_ENTRY) -#endif - - GENERATE_VM_ADDRESS_LAST_ENTRY() -}; - // This is used both to check the types of referenced fields and, in // debug builds, to ensure that all of the field types are present. void @@ -3575,11 +3375,6 @@ JNIEXPORT VMLongConstantEntry* gHotSpotVMLongConstants = VMStructs::localHotSpot JNIEXPORT uint64_t gHotSpotVMLongConstantEntryNameOffset = offset_of(VMLongConstantEntry, name); JNIEXPORT uint64_t gHotSpotVMLongConstantEntryValueOffset = offset_of(VMLongConstantEntry, value); JNIEXPORT uint64_t gHotSpotVMLongConstantEntryArrayStride = STRIDE(gHotSpotVMLongConstants); - -JNIEXPORT VMAddressEntry* gHotSpotVMAddresses = VMStructs::localHotSpotVMAddresses; -JNIEXPORT uint64_t gHotSpotVMAddressEntryNameOffset = offset_of(VMAddressEntry, name); -JNIEXPORT uint64_t gHotSpotVMAddressEntryValueOffset = offset_of(VMAddressEntry, value); -JNIEXPORT uint64_t gHotSpotVMAddressEntryArrayStride = STRIDE(gHotSpotVMAddresses); } #ifdef ASSERT @@ -3687,11 +3482,6 @@ void VMStructs::test() { &long_last_entry, sizeof(VMLongConstantEntry)) == 0, "Incorrect last entry in localHotSpotVMLongConstants"); - static VMAddressEntry address_last_entry = GENERATE_VM_ADDRESS_LAST_ENTRY(); - assert(memcmp(&localHotSpotVMAddresses[sizeof(localHotSpotVMAddresses) / sizeof(VMAddressEntry) - 1], - &address_last_entry, - sizeof(VMAddressEntry)) == 0, "Incorrect last entry in localHotSpotVMAddresses"); - // Check for duplicate entries in type array for (int i = 0; localHotSpotVMTypes[i].typeName != NULL; i++) { diff --git a/hotspot/src/share/vm/runtime/vmStructs.hpp b/hotspot/src/share/vm/runtime/vmStructs.hpp index 369ff9e9426..4f9f31dcd3e 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.hpp +++ b/hotspot/src/share/vm/runtime/vmStructs.hpp @@ -143,4 +143,151 @@ private: static int findType(const char* typeName); }; +// This utility macro quotes the passed string +#define QUOTE(x) #x + +//-------------------------------------------------------------------------------- +// VMStructEntry macros +// + +// This macro generates a VMStructEntry line for a nonstatic field +#define GENERATE_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + { QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 0, offset_of(typeName, fieldName), NULL }, + +// This macro generates a VMStructEntry line for a static field +#define GENERATE_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + { QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 1, 0, &typeName::fieldName }, + +// This macro generates a VMStructEntry line for a static pointer volatile field, +// e.g.: "static ObjectMonitor * volatile gBlockList;" +#define GENERATE_STATIC_PTR_VOLATILE_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + { QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 1, 0, (void *)&typeName::fieldName }, + +// This macro generates a VMStructEntry line for an unchecked +// nonstatic field, in which the size of the type is also specified. +// The type string is given as NULL, indicating an "opaque" type. +#define GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, size) \ + { QUOTE(typeName), QUOTE(fieldName), NULL, 0, offset_of(typeName, fieldName), NULL }, + +// This macro generates a VMStructEntry line for an unchecked +// static field, in which the size of the type is also specified. +// The type string is given as NULL, indicating an "opaque" type. +#define GENERATE_UNCHECKED_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, size) \ + { QUOTE(typeName), QUOTE(fieldName), NULL, 1, 0, (void*) &typeName::fieldName }, + +// This macro generates the sentinel value indicating the end of the list +#define GENERATE_VM_STRUCT_LAST_ENTRY() \ + { NULL, NULL, NULL, 0, 0, NULL } + +// This macro checks the type of a VMStructEntry by comparing pointer types +#define CHECK_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + {typeName *dummyObj = NULL; type* dummy = &dummyObj->fieldName; \ + assert(offset_of(typeName, fieldName) < sizeof(typeName), "Illegal nonstatic struct entry, field offset too large"); } + +// This macro checks the type of a volatile VMStructEntry by comparing pointer types +#define CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + {typedef type dummyvtype; typeName *dummyObj = NULL; volatile dummyvtype* dummy = &dummyObj->fieldName; } + +// This macro checks the type of a static VMStructEntry by comparing pointer types +#define CHECK_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + {type* dummy = &typeName::fieldName; } + +// This macro checks the type of a static pointer volatile VMStructEntry by comparing pointer types, +// e.g.: "static ObjectMonitor * volatile gBlockList;" +#define CHECK_STATIC_PTR_VOLATILE_VM_STRUCT_ENTRY(typeName, fieldName, type) \ + {type volatile * dummy = &typeName::fieldName; } + +// This macro ensures the type of a field and its containing type are +// present in the type table. The assertion string is shorter than +// preferable because (incredibly) of a bug in Solstice NFS client +// which seems to prevent very long lines from compiling. This assertion +// means that an entry in VMStructs::localHotSpotVMStructs[] was not +// found in VMStructs::localHotSpotVMTypes[]. +#define ENSURE_FIELD_TYPE_PRESENT(typeName, fieldName, type) \ + { assert(findType(QUOTE(typeName)) != 0, "type \"" QUOTE(typeName) "\" not found in type table"); \ + assert(findType(QUOTE(type)) != 0, "type \"" QUOTE(type) "\" not found in type table"); } + +// This is a no-op macro for unchecked fields +#define CHECK_NO_OP(a, b, c) + + +//-------------------------------------------------------------------------------- +// VMTypeEntry macros +// + +#define GENERATE_VM_TYPE_ENTRY(type, superclass) \ + { QUOTE(type), QUOTE(superclass), 0, 0, 0, sizeof(type) }, + +#define GENERATE_TOPLEVEL_VM_TYPE_ENTRY(type) \ + { QUOTE(type), NULL, 0, 0, 0, sizeof(type) }, + +#define GENERATE_OOP_VM_TYPE_ENTRY(type) \ + { QUOTE(type), NULL, 1, 0, 0, sizeof(type) }, + +#define GENERATE_INTEGER_VM_TYPE_ENTRY(type) \ + { QUOTE(type), NULL, 0, 1, 0, sizeof(type) }, + +#define GENERATE_UNSIGNED_INTEGER_VM_TYPE_ENTRY(type) \ + { QUOTE(type), NULL, 0, 1, 1, sizeof(type) }, + +#define GENERATE_VM_TYPE_LAST_ENTRY() \ + { NULL, NULL, 0, 0, 0, 0 } + +#define CHECK_VM_TYPE_ENTRY(type, superclass) \ + { type* dummyObj = NULL; superclass* dummySuperObj = dummyObj; } + +#define CHECK_VM_TYPE_NO_OP(a) +#define CHECK_SINGLE_ARG_VM_TYPE_NO_OP(a) + + +//-------------------------------------------------------------------------------- +// VMIntConstantEntry macros +// + +#define GENERATE_VM_INT_CONSTANT_ENTRY(name) \ + { QUOTE(name), (int32_t) name }, + +#define GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY(name, value) \ + { (name), (int32_t)(value) }, + +#define GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY(name, value) \ + { name, (int32_t) value }, + +// This macro generates the sentinel value indicating the end of the list +#define GENERATE_VM_INT_CONSTANT_LAST_ENTRY() \ + { NULL, 0 } + + +//-------------------------------------------------------------------------------- +// VMLongConstantEntry macros +// + +#define GENERATE_VM_LONG_CONSTANT_ENTRY(name) \ + { QUOTE(name), name }, + +#define GENERATE_PREPROCESSOR_VM_LONG_CONSTANT_ENTRY(name, value) \ + { name, value }, + +// This macro generates the sentinel value indicating the end of the list +#define GENERATE_VM_LONG_CONSTANT_LAST_ENTRY() \ + { NULL, 0 } + + +//-------------------------------------------------------------------------------- +// VMAddressEntry macros +// + +#define GENERATE_VM_ADDRESS_ENTRY(name) \ + { QUOTE(name), (void*) (name) }, + +#define GENERATE_PREPROCESSOR_VM_ADDRESS_ENTRY(name, value) \ + { name, (void*) (value) }, + +#define GENERATE_VM_FUNCTION_ENTRY(name) \ + { QUOTE(name), CAST_FROM_FN_PTR(void*, &(name)) }, + +// This macro generates the sentinel value indicating the end of the list +#define GENERATE_VM_ADDRESS_LAST_ENTRY() \ + { NULL, NULL } + #endif // SHARE_VM_RUNTIME_VMSTRUCTS_HPP diff --git a/hotspot/src/share/vm/utilities/array.hpp b/hotspot/src/share/vm/utilities/array.hpp index 8df72304ef0..f759fe1c03f 100644 --- a/hotspot/src/share/vm/utilities/array.hpp +++ b/hotspot/src/share/vm/utilities/array.hpp @@ -304,6 +304,7 @@ template class Array: public MetaspaceObj { friend class MetadataFactory; friend class VMStructs; + friend class JVMCIVMStructs; friend class MethodHandleCompiler; // special case friend class WhiteBox; protected: diff --git a/hotspot/src/share/vm/utilities/exceptions.hpp b/hotspot/src/share/vm/utilities/exceptions.hpp index 02d9110ef74..5983f5e32f9 100644 --- a/hotspot/src/share/vm/utilities/exceptions.hpp +++ b/hotspot/src/share/vm/utilities/exceptions.hpp @@ -59,6 +59,7 @@ class JavaCallArguments; class ThreadShadow: public CHeapObj { friend class VMStructs; + friend class JVMCIVMStructs; protected: oop _pending_exception; // Thread has gc actions. From 1a135175c4a0c511c8dda22b4243c33e30d7062d Mon Sep 17 00:00:00 2001 From: Alexander Vorobyev Date: Tue, 15 Dec 2015 17:31:18 +0300 Subject: [PATCH 056/215] 8079667: port vm/compiler/AESIntrinsics/CheckIntrinsics into jtreg Reviewed-by: kvn --- .../compiler/cpuflags/AESIntrinsicsBase.java | 65 +++++ .../TestAESIntrinsicsOnSupportedConfig.java | 254 ++++++++++++++++++ .../TestAESIntrinsicsOnUnsupportedConfig.java | 112 ++++++++ .../predicate/AESSupportPredicate.java | 37 +++ .../test/lib/cli/CommandLineOptionTest.java | 48 +++- 5 files changed, 511 insertions(+), 5 deletions(-) create mode 100644 hotspot/test/compiler/cpuflags/AESIntrinsicsBase.java create mode 100644 hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java create mode 100644 hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java create mode 100644 hotspot/test/compiler/cpuflags/predicate/AESSupportPredicate.java diff --git a/hotspot/test/compiler/cpuflags/AESIntrinsicsBase.java b/hotspot/test/compiler/cpuflags/AESIntrinsicsBase.java new file mode 100644 index 00000000000..8e8deda71bd --- /dev/null +++ b/hotspot/test/compiler/cpuflags/AESIntrinsicsBase.java @@ -0,0 +1,65 @@ +/* + * 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. + * + */ +import jdk.test.lib.cli.CommandLineOptionTest; +import predicate.AESSupportPredicate; + +import java.util.Arrays; +import java.util.function.BooleanSupplier; + +public abstract class AESIntrinsicsBase extends CommandLineOptionTest { + public static final BooleanSupplier AES_SUPPORTED_PREDICATE + = new AESSupportPredicate(); + public static final String CIPHER_INTRINSIC = "com\\.sun\\.crypto\\" + + ".provider\\.CipherBlockChaining::" + + "(implEncrypt|implDecrypt) \\([0-9]+ bytes\\)\\s+\\(intrinsic[,\\)]"; + public static final String AES_INTRINSIC = "com\\.sun\\.crypto\\" + + ".provider\\.AESCrypt::(implEncryptBlock|implDecryptBlock) \\([0-9]+ " + + "bytes\\)\\s+\\(intrinsic[,\\)]"; + public static final String USE_AES = "UseAES"; + public static final String USE_AES_INTRINSICS = "UseAESIntrinsics"; + public static final String USE_SSE = "UseSSE"; + public static final String USE_VIS = "UseVIS"; + public static final String[] TEST_AES_CMD + = {"-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PrintFlagsFinal", + "-Xbatch","-XX:+UnlockDiagnosticVMOptions", + "-XX:+PrintIntrinsics", "-DcheckOutput=true", "-Dmode=CBC", + "TestAESMain"}; + + protected AESIntrinsicsBase(BooleanSupplier predicate) { + super(predicate); + } + + /** + * Prepares command for TestAESMain execution. + * @param args flags that must be added to command + * @return command for TestAESMain execution + */ + public static String[] prepareArguments(String... args) { + String[] command = Arrays.copyOf(args, TEST_AES_CMD.length + + args.length); + System.arraycopy(TEST_AES_CMD, 0, command, args.length, + TEST_AES_CMD.length); + return command; + } +} diff --git a/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java b/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java new file mode 100644 index 00000000000..4d655dee023 --- /dev/null +++ b/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java @@ -0,0 +1,254 @@ +/* + * 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. + * + */ +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.Platform; +import jdk.test.lib.ProcessTools; + +/* + * @test + * @library /testlibrary /../../test/lib /compiler/whitebox + * /compiler/testlibrary /compiler/codegen/7184394 + * @modules java.base/sun.misc + * java.management + * @build TestAESIntrinsicsOnSupportedConfig TestAESMain + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -Xbatch + * TestAESIntrinsicsOnSupportedConfig + */ +public class TestAESIntrinsicsOnSupportedConfig extends AESIntrinsicsBase { + + /** + * Constructs new TestAESIntrinsicsOnSupportedConfig that will be executed + * only if AESSupportPredicate returns true + */ + private TestAESIntrinsicsOnSupportedConfig() { + super(AESIntrinsicsBase.AES_SUPPORTED_PREDICATE); + } + + @Override + protected void runTestCases() throws Throwable { + testUseAES(); + testUseAESUseSSE2(); + testUseAESUseVIS2(); + testNoUseAES(); + testNoUseAESUseSSE2(); + testNoUseAESUseVIS2(); + testNoUseAESIntrinsic(); + } + + /** + * Test checks following situation:
+ * UseAES flag is set to true, TestAESMain is executed
+ * Expected result: UseAESIntrinsics flag is set to true
+ * If vm type is server then output should contain intrinsics usage
+ * + * @throws Throwable + */ + private void testUseAES() throws Throwable { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES, true))); + final String errorMessage = "Case testUseAES failed"; + if (Platform.isServer()) { + verifyOutput(new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, null, errorMessage, + outputAnalyzer); + } else { + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, errorMessage, + outputAnalyzer); + } + verifyOptionValue(AESIntrinsicsBase.USE_AES, "true", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "true", + errorMessage, outputAnalyzer); + } + + /** + * Test checks following situation:
+ * UseAES flag is set to true, UseSSE flag is set to 2, + * Platform should support UseSSE (x86 or x64)
+ * TestAESMain is executed
+ * Expected result: UseAESIntrinsics flag is set to false
+ * Output shouldn't contain intrinsics usage
+ * + * @throws Throwable + */ + private void testUseAESUseSSE2() throws Throwable { + if (Platform.isX86() || Platform.isX64()) { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES_INTRINSICS, true), + prepareNumericFlag(AESIntrinsicsBase.USE_SSE, 2))); + final String errorMessage = "Case testUseAESUseSSE2 failed"; + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "true", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_SSE, "2", errorMessage, + outputAnalyzer); + } + } + + /** + * Test checks following situation:
+ * UseAES flag is set to false, UseSSE flag is set to 2, + * Platform should support UseSSE (x86 or x64)
+ * TestAESMain is executed
+ * Expected result: UseAESIntrinsics flag is set to false
+ * Output shouldn't contain intrinsics usage
+ * + * @throws Throwable + */ + private void testNoUseAESUseSSE2() throws Throwable { + if (Platform.isX86() || Platform.isX64()) { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES, false), + prepareNumericFlag(AESIntrinsicsBase.USE_SSE, 2))); + final String errorMessage = "Case testNoUseAESUseSSE2 failed"; + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "false", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_SSE, "2", errorMessage, + outputAnalyzer); + } + } + + /** + * Test checks following situation:
+ * UseAES flag is set to true, UseVIS flag is set to 2, + * Platform should support UseVIS (sparc)
+ * TestAESMain is executed
+ * Expected result: UseAESIntrinsics flag is set to false
+ * Output shouldn't contain intrinsics usage
+ * + * @throws Throwable + */ + private void testUseAESUseVIS2() throws Throwable { + if (Platform.isSparc()) { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES_INTRINSICS, true), + prepareNumericFlag(AESIntrinsicsBase.USE_VIS, 2))); + final String errorMessage = "Case testUseAESUseVIS2 failed"; + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "true", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_VIS, "2", errorMessage, + outputAnalyzer); + } + } + + + /** + * Test checks following situation:
+ * UseAES flag is set to false, UseVIS flag is set to 2, + * Platform should support UseVIS (sparc)
+ * TestAESMain is executed
+ * Expected result: UseAESIntrinsics flag is set to false
+ * Output shouldn't contain intrinsics usage
+ * + * @throws Throwable + */ + private void testNoUseAESUseVIS2() throws Throwable { + if (Platform.isSparc()) { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES, false), + prepareNumericFlag(AESIntrinsicsBase.USE_VIS, 2))); + final String errorMessage = "Case testNoUseAESUseVIS2 failed"; + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "false", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_VIS, "2", errorMessage, + outputAnalyzer); + } + } + + /** + * Test checks following situation:
+ * UseAES flag is set to false, TestAESMain is executed
+ * Expected result: UseAESIntrinsics flag is set to false
+ * Output shouldn't contain intrinsics usage
+ * + * @throws Throwable + */ + private void testNoUseAES() throws Throwable { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES, false))); + final String errorMessage = "Case testNoUseAES failed"; + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "false", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + } + + /** + * Test checks following situation:
+ * UseAESIntrinsics flag is set to false, TestAESMain is executed
+ * Expected result: UseAES flag is set to true
+ * Output shouldn't contain intrinsics usage
+ * + * @throws Throwable + */ + private void testNoUseAESIntrinsic() throws Throwable { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + prepareArguments(prepareBooleanFlag(AESIntrinsicsBase + .USE_AES_INTRINSICS, false))); + final String errorMessage = "Case testNoUseAESIntrinsic failed"; + verifyOutput(null, new String[]{AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "true", errorMessage, + outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + } + + public static void main(String args[]) throws Throwable { + new TestAESIntrinsicsOnSupportedConfig().test(); + } +} diff --git a/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java b/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java new file mode 100644 index 00000000000..fa5e3aaf46e --- /dev/null +++ b/hotspot/test/compiler/cpuflags/TestAESIntrinsicsOnUnsupportedConfig.java @@ -0,0 +1,112 @@ +/* + * 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. + * + */ + +import jdk.test.lib.cli.predicate.NotPredicate; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +/* + * @test + * @library /testlibrary /../../test/lib /compiler/whitebox + * /compiler/testlibrary /compiler/codegen/7184394 + * @modules java.base/sun.misc + * java.management + * @build TestAESIntrinsicsOnUnsupportedConfig TestAESMain + * @run main ClassFileInstaller + * sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -Xbatch TestAESIntrinsicsOnUnsupportedConfig + */ +public class TestAESIntrinsicsOnUnsupportedConfig extends AESIntrinsicsBase { + + private static final String INTRINSICS_NOT_AVAILABLE_MSG = "warning: AES " + + "intrinsics are not available on this CPU"; + private static final String AES_NOT_AVAILABLE_MSG = "warning: AES " + + "instructions are not available on this CPU"; + + /** + * Constructs new TestAESIntrinsicsOnUnsupportedConfig that will be + * executed only if AESSupportPredicate returns false + */ + private TestAESIntrinsicsOnUnsupportedConfig() { + super(new NotPredicate(AESIntrinsicsBase.AES_SUPPORTED_PREDICATE)); + } + + @Override + protected void runTestCases() throws Throwable { + testUseAES(); + testUseAESIntrinsics(); + } + + /** + * Test checks following situation:
+ * UseAESIntrinsics flag is set to true, TestAESMain is executed
+ * Expected result: UseAESIntrinsics flag is set to false
+ * UseAES flag is set to false
+ * Output shouldn't contain intrinsics usage
+ * Output should contain message about intrinsics unavailability + * @throws Throwable + */ + private void testUseAESIntrinsics() throws Throwable { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + AESIntrinsicsBase.prepareArguments(prepareBooleanFlag( + AESIntrinsicsBase.USE_AES_INTRINSICS, true))); + final String errorMessage = "Case testUseAESIntrinsics failed"; + verifyOutput(new String[] {INTRINSICS_NOT_AVAILABLE_MSG}, + new String[] {AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "false", errorMessage, + outputAnalyzer); + } + + /** + * Test checks following situation:
+ * UseAESIntrinsics flag is set to true, TestAESMain is executed
+ * Expected result: UseAES flag is set to false
+ * UseAES flag is set to false
+ * Output shouldn't contain intrinsics usage
+ * Output should contain message about AES unavailability
+ * @throws Throwable + */ + private void testUseAES() throws Throwable { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm( + AESIntrinsicsBase.prepareArguments(prepareBooleanFlag + (AESIntrinsicsBase.USE_AES, true))); + final String errorMessage = "Case testUseAES failed"; + verifyOutput(new String[] {AES_NOT_AVAILABLE_MSG}, + new String[] {AESIntrinsicsBase.CIPHER_INTRINSIC, + AESIntrinsicsBase.AES_INTRINSIC}, errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES_INTRINSICS, "false", + errorMessage, outputAnalyzer); + verifyOptionValue(AESIntrinsicsBase.USE_AES, "false", errorMessage, + outputAnalyzer); + } + + public static void main(String args[]) throws Throwable { + new TestAESIntrinsicsOnUnsupportedConfig().test(); + } +} diff --git a/hotspot/test/compiler/cpuflags/predicate/AESSupportPredicate.java b/hotspot/test/compiler/cpuflags/predicate/AESSupportPredicate.java new file mode 100644 index 00000000000..7b4f78b8d13 --- /dev/null +++ b/hotspot/test/compiler/cpuflags/predicate/AESSupportPredicate.java @@ -0,0 +1,37 @@ +/* + * 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. + * + */ +package predicate; + +import sun.hotspot.cpuinfo.CPUInfo; +import java.util.function.BooleanSupplier; + +public class AESSupportPredicate implements BooleanSupplier { + + private static final String AES = "aes"; + + @Override + public boolean getAsBoolean() { + return CPUInfo.getFeatures().contains(AES); + } +} diff --git a/hotspot/test/testlibrary/jdk/test/lib/cli/CommandLineOptionTest.java b/hotspot/test/testlibrary/jdk/test/lib/cli/CommandLineOptionTest.java index 031d58a4b54..e1bb112ceb3 100644 --- a/hotspot/test/testlibrary/jdk/test/lib/cli/CommandLineOptionTest.java +++ b/hotspot/test/testlibrary/jdk/test/lib/cli/CommandLineOptionTest.java @@ -121,7 +121,27 @@ public abstract class CommandLineOptionTest { throw new AssertionError(errorMessage, e); } + verifyOutput(expectedMessages, unexpectedMessages, + wrongWarningMessage, outputAnalyzer); + } + /** + * Verifies that JVM startup behavior matches our expectations. + * + * @param expectedMessages an array of patterns that should occur in JVM + * output. If {@code null} then + * JVM output could be empty. + * @param unexpectedMessages an array of patterns that should not occur + * in JVM output. If {@code null} then + * JVM output could be empty. + * @param wrongWarningMessage message that will be shown if messages are + * not as expected. + * @param outputAnalyzer OutputAnalyzer instance + * @throws AssertionError if verification fails. + */ + public static void verifyOutput(String[] expectedMessages, + String[] unexpectedMessages, String wrongWarningMessage, + OutputAnalyzer outputAnalyzer) { if (expectedMessages != null) { for (String expectedMessage : expectedMessages) { try { @@ -199,7 +219,7 @@ public abstract class CommandLineOptionTest { public static void verifyOptionValue(String optionName, String expectedValue, String optionErrorString, String... additionalVMOpts) throws Throwable { - verifyOptionValue(optionName, expectedValue, optionErrorString, + verifyOptionValue(optionName, expectedValue, optionErrorString, true, additionalVMOpts); } @@ -247,12 +267,30 @@ public abstract class CommandLineOptionTest { optionName); throw new AssertionError(errorMessage, e); } + verifyOptionValue(optionName, expectedValue, optionErrorString, + outputAnalyzer); + } + + /** + * Verifies that value of specified JVM option is the same as + * expected value. + * + * @param optionName a name of tested option. + * @param expectedValue expected value of tested option. + * @param optionErrorString message will be shown if option value is not + * as expected. + * @param outputAnalyzer OutputAnalyzer instance + * @throws AssertionError if verification fails + */ + public static void verifyOptionValue(String optionName, + String expectedValue, String optionErrorString, + OutputAnalyzer outputAnalyzer) { try { - outputAnalyzer.shouldMatch(String.format( - CommandLineOptionTest.PRINT_FLAGS_FINAL_FORMAT, - optionName, expectedValue)); + outputAnalyzer.shouldMatch(String.format( + CommandLineOptionTest.PRINT_FLAGS_FINAL_FORMAT, + optionName, expectedValue)); } catch (RuntimeException e) { - String errorMessage = String.format( + String errorMessage = String.format( "Option '%s' is expected to have '%s' value%n%s", optionName, expectedValue, optionErrorString); From dd5481cbbc702b33b4cff08a2cc2cb7e18fccea6 Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Tue, 15 Dec 2015 19:18:05 +0000 Subject: [PATCH 057/215] 8145438: Guarantee failures since 8144028: Use AArch64 bit-test instructions in C2 Implement short and long versions of bit test instructions. Reviewed-by: kvn --- hotspot/src/cpu/aarch64/vm/aarch64.ad | 122 ++++++++++++++---- .../aarch64/vm/c1_MacroAssembler_aarch64.hpp | 1 + .../cpu/aarch64/vm/interp_masm_aarch64.cpp | 5 +- .../cpu/aarch64/vm/macroAssembler_aarch64.hpp | 26 ++++ hotspot/src/share/vm/adlc/formssel.cpp | 3 +- 5 files changed, 127 insertions(+), 30 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index b6a1a242038..f19eb0e71c7 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -3484,10 +3484,14 @@ int Matcher::regnum_to_fpu_offset(int regnum) return 0; } -bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) -{ - Unimplemented(); - return false; +// Is this branch offset short enough that a short branch can be used? +// +// NOTE: If the platform does not provide any short branch variants, then +// this method should return false for offset 0. +bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) { + // The passed offset is relative to address of the branch. + + return (-32768 <= offset && offset < 32768); } const bool Matcher::isSimpleConstant64(jlong value) { @@ -13845,7 +13849,8 @@ instruct cmpP_narrowOop_imm0_branch(cmpOp cmp, iRegN oop, immP0 zero, label labl // Test bit and Branch -instruct cmpL_branch_sign(cmpOp cmp, iRegL op1, immL0 op2, label labl, rFlagsReg cr) %{ +// Patterns for short (< 32KiB) variants +instruct cmpL_branch_sign(cmpOp cmp, iRegL op1, immL0 op2, label labl) %{ match(If cmp (CmpL op1 op2)); predicate(n->in(1)->as_Bool()->_test._test == BoolTest::lt || n->in(1)->as_Bool()->_test._test == BoolTest::ge); @@ -13855,16 +13860,15 @@ instruct cmpL_branch_sign(cmpOp cmp, iRegL op1, immL0 op2, label labl, rFlagsReg format %{ "cb$cmp $op1, $labl # long" %} ins_encode %{ Label* L = $labl$$label; - Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; - if (cond == Assembler::LT) - __ tbnz($op1$$Register, 63, *L); - else - __ tbz($op1$$Register, 63, *L); + Assembler::Condition cond = + ((Assembler::Condition)$cmp$$cmpcode == Assembler::LT) ? Assembler::NE : Assembler::EQ; + __ tbr(cond, $op1$$Register, 63, *L); %} ins_pipe(pipe_cmp_branch); + ins_short_branch(1); %} -instruct cmpI_branch_sign(cmpOp cmp, iRegIorL2I op1, immI0 op2, label labl, rFlagsReg cr) %{ +instruct cmpI_branch_sign(cmpOp cmp, iRegIorL2I op1, immI0 op2, label labl) %{ match(If cmp (CmpI op1 op2)); predicate(n->in(1)->as_Bool()->_test._test == BoolTest::lt || n->in(1)->as_Bool()->_test._test == BoolTest::ge); @@ -13874,16 +13878,15 @@ instruct cmpI_branch_sign(cmpOp cmp, iRegIorL2I op1, immI0 op2, label labl, rFla format %{ "cb$cmp $op1, $labl # int" %} ins_encode %{ Label* L = $labl$$label; - Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; - if (cond == Assembler::LT) - __ tbnz($op1$$Register, 31, *L); - else - __ tbz($op1$$Register, 31, *L); + Assembler::Condition cond = + ((Assembler::Condition)$cmp$$cmpcode == Assembler::LT) ? Assembler::NE : Assembler::EQ; + __ tbr(cond, $op1$$Register, 31, *L); %} ins_pipe(pipe_cmp_branch); + ins_short_branch(1); %} -instruct cmpL_branch_bit(cmpOp cmp, iRegL op1, immL op2, immL0 op3, label labl, rFlagsReg cr) %{ +instruct cmpL_branch_bit(cmpOp cmp, iRegL op1, immL op2, immL0 op3, label labl) %{ match(If cmp (CmpL (AndL op1 op2) op3)); predicate((n->in(1)->as_Bool()->_test._test == BoolTest::ne || n->in(1)->as_Bool()->_test._test == BoolTest::eq) @@ -13896,15 +13899,13 @@ instruct cmpL_branch_bit(cmpOp cmp, iRegL op1, immL op2, immL0 op3, label labl, Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; int bit = exact_log2($op2$$constant); - if (cond == Assembler::EQ) - __ tbz($op1$$Register, bit, *L); - else - __ tbnz($op1$$Register, bit, *L); + __ tbr(cond, $op1$$Register, bit, *L); %} ins_pipe(pipe_cmp_branch); + ins_short_branch(1); %} -instruct cmpI_branch_bit(cmpOp cmp, iRegIorL2I op1, immI op2, immI0 op3, label labl, rFlagsReg cr) %{ +instruct cmpI_branch_bit(cmpOp cmp, iRegIorL2I op1, immI op2, immI0 op3, label labl) %{ match(If cmp (CmpI (AndI op1 op2) op3)); predicate((n->in(1)->as_Bool()->_test._test == BoolTest::ne || n->in(1)->as_Bool()->_test._test == BoolTest::eq) @@ -13917,10 +13918,79 @@ instruct cmpI_branch_bit(cmpOp cmp, iRegIorL2I op1, immI op2, immI0 op3, label l Label* L = $labl$$label; Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; int bit = exact_log2($op2$$constant); - if (cond == Assembler::EQ) - __ tbz($op1$$Register, bit, *L); - else - __ tbnz($op1$$Register, bit, *L); + __ tbr(cond, $op1$$Register, bit, *L); + %} + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +// And far variants +instruct far_cmpL_branch_sign(cmpOp cmp, iRegL op1, immL0 op2, label labl) %{ + match(If cmp (CmpL op1 op2)); + predicate(n->in(1)->as_Bool()->_test._test == BoolTest::lt + || n->in(1)->as_Bool()->_test._test == BoolTest::ge); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "cb$cmp $op1, $labl # long" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = + ((Assembler::Condition)$cmp$$cmpcode == Assembler::LT) ? Assembler::NE : Assembler::EQ; + __ tbr(cond, $op1$$Register, 63, *L, /*far*/true); + %} + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpI_branch_sign(cmpOp cmp, iRegIorL2I op1, immI0 op2, label labl) %{ + match(If cmp (CmpI op1 op2)); + predicate(n->in(1)->as_Bool()->_test._test == BoolTest::lt + || n->in(1)->as_Bool()->_test._test == BoolTest::ge); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "cb$cmp $op1, $labl # int" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = + ((Assembler::Condition)$cmp$$cmpcode == Assembler::LT) ? Assembler::NE : Assembler::EQ; + __ tbr(cond, $op1$$Register, 31, *L, /*far*/true); + %} + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpL_branch_bit(cmpOp cmp, iRegL op1, immL op2, immL0 op3, label labl) %{ + match(If cmp (CmpL (AndL op1 op2) op3)); + predicate((n->in(1)->as_Bool()->_test._test == BoolTest::ne + || n->in(1)->as_Bool()->_test._test == BoolTest::eq) + && is_power_of_2(n->in(2)->in(1)->in(2)->get_long())); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "tb$cmp $op1, $op2, $labl" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; + int bit = exact_log2($op2$$constant); + __ tbr(cond, $op1$$Register, bit, *L, /*far*/true); + %} + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpI_branch_bit(cmpOp cmp, iRegIorL2I op1, immI op2, immI0 op3, label labl) %{ + match(If cmp (CmpI (AndI op1 op2) op3)); + predicate((n->in(1)->as_Bool()->_test._test == BoolTest::ne + || n->in(1)->as_Bool()->_test._test == BoolTest::eq) + && is_power_of_2(n->in(2)->in(1)->in(2)->get_int())); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "tb$cmp $op1, $op2, $labl" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; + int bit = exact_log2($op2$$constant); + __ tbr(cond, $op1$$Register, bit, *L, /*far*/true); %} ins_pipe(pipe_cmp_branch); %} diff --git a/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp index fe41973b106..24389643ca0 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/c1_MacroAssembler_aarch64.hpp @@ -27,6 +27,7 @@ #define CPU_AARCH64_VM_C1_MACROASSEMBLER_AARCH64_HPP using MacroAssembler::build_frame; +using MacroAssembler::null_check; // C1_MacroAssembler contains high-level macros for C1 diff --git a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp index d463f059978..73f35a6bb44 100644 --- a/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/interp_masm_aarch64.cpp @@ -1354,9 +1354,8 @@ void InterpreterMacroAssembler::notify_method_entry() { // the code to check if the event should be sent. if (JvmtiExport::can_post_interpreter_events()) { Label L; - ldr(r3, Address(rthread, JavaThread::interp_only_mode_offset())); - tst(r3, ~0); - br(Assembler::EQ, L); + ldrw(r3, Address(rthread, JavaThread::interp_only_mode_offset())); + cbzw(r3, L); call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_entry)); bind(L); diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp index 54c608fada0..ade0ba0eb97 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp @@ -487,6 +487,32 @@ public: orr(Vd, T, Vn, Vn); } +public: + + // Generalized Test Bit And Branch, including a "far" variety which + // spans more than 32KiB. + void tbr(Condition cond, Register Rt, int bitpos, Label &dest, bool far = false) { + assert(cond == EQ || cond == NE, "must be"); + + if (far) + cond = ~cond; + + void (Assembler::* branch)(Register Rt, int bitpos, Label &L); + if (cond == Assembler::EQ) + branch = &Assembler::tbz; + else + branch = &Assembler::tbnz; + + if (far) { + Label L; + (this->*branch)(Rt, bitpos, L); + b(dest); + bind(L); + } else { + (this->*branch)(Rt, bitpos, dest); + } + } + // macro instructions for accessing and updating floating point // status register // diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp index 82ba5f9e2d7..90c965bfa88 100644 --- a/hotspot/src/share/vm/adlc/formssel.cpp +++ b/hotspot/src/share/vm/adlc/formssel.cpp @@ -1246,7 +1246,8 @@ bool InstructForm::check_branch_variant(ArchDesc &AD, InstructForm *short_branch !is_short_branch() && // Don't match another short branch variant reduce_result() != NULL && strcmp(reduce_result(), short_branch->reduce_result()) == 0 && - _matrule->equivalent(AD.globalNames(), short_branch->_matrule)) { + _matrule->equivalent(AD.globalNames(), short_branch->_matrule) && + equivalent_predicates(this, short_branch)) { // The instructions are equivalent. // Now verify that both instructions have the same parameters and From edb2af6a6d955e466cf66dcfcf51bb6b7bdcde9c Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Wed, 16 Dec 2015 11:35:59 +0000 Subject: [PATCH 058/215] 8144582: AArch64 does not generate correct branch profile data Reviewed-by: kvn --- hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp index fb339033869..c2da6264f6c 100644 --- a/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/templateInterpreter_aarch64.cpp @@ -392,7 +392,7 @@ void InterpreterGenerator::generate_counter_incr( __ br(Assembler::LT, *profile_method_continue); // if no method data exists, go to profile_method - __ test_method_data_pointer(r0, *profile_method); + __ test_method_data_pointer(rscratch2, *profile_method); } { From 07512e7aece900b81032c429abff38e580137bce Mon Sep 17 00:00:00 2001 From: Andrew Haley Date: Wed, 16 Dec 2015 13:21:19 +0000 Subject: [PATCH 059/215] 8145553: Fix warnings in AArch64 directory Reviewed-by: kvn --- .../src/cpu/aarch64/vm/assembler_aarch64.hpp | 8 +--- .../aarch64/vm/c1_LIRAssembler_aarch64.cpp | 40 +++++++++++++------ .../aarch64/vm/c1_LIRGenerator_aarch64.cpp | 1 + .../cpu/aarch64/vm/interpreter_aarch64.cpp | 1 + .../aarch64/vm/jniFastGetField_aarch64.cpp | 2 + 5 files changed, 33 insertions(+), 19 deletions(-) diff --git a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp index 76fdf876f90..ca617716562 100644 --- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp @@ -135,15 +135,10 @@ REGISTER_DECLARATION(Register, rlocals, r24); // bytecode pointer REGISTER_DECLARATION(Register, rbcp, r22); // Dispatch table base -REGISTER_DECLARATION(Register, rdispatch, r21); +REGISTER_DECLARATION(Register, rdispatch, r21); // Java stack pointer REGISTER_DECLARATION(Register, esp, r20); -// TODO : x86 uses rbp to save SP in method handle code -// we may need to do the same with fp -// JSR 292 fixed register usages: -//REGISTER_DECLARATION(Register, r_mh_SP_save, r29); - #define assert_cond(ARG1) assert(ARG1, #ARG1) namespace asm_util { @@ -551,6 +546,7 @@ class Address VALUE_OBJ_CLASS_SPEC { size = 0; break; default: ShouldNotReachHere(); + size = 0; // unreachable } } else { size = i->get(31, 31); diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp index 119d113aac5..210b29e1e75 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp @@ -173,6 +173,7 @@ static jlong as_long(LIR_Opr data) { break; default: ShouldNotReachHere(); + result = 0; // unreachable } return result; } @@ -720,6 +721,7 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi break; default: ShouldNotReachHere(); + insn = &Assembler::str; // unreachable } if (info) add_debug_info_for_null_check_here(info); @@ -1110,6 +1112,7 @@ void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) { case lir_cond_greaterEqual: acond = (is_unordered ? Assembler::HS : Assembler::GE); break; case lir_cond_greater: acond = (is_unordered ? Assembler::HI : Assembler::GT); break; default: ShouldNotReachHere(); + acond = Assembler::EQ; // unreachable } } else { switch (op->cond()) { @@ -1121,7 +1124,8 @@ void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) { case lir_cond_greater: acond = Assembler::GT; break; case lir_cond_belowEqual: acond = Assembler::LS; break; case lir_cond_aboveEqual: acond = Assembler::HS; break; - default: ShouldNotReachHere(); + default: ShouldNotReachHere(); + acond = Assembler::EQ; // unreachable } } __ br(acond,*(op->label())); @@ -1313,7 +1317,9 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L ciMethodData* md; ciProfileData* data; - if (op->should_profile()) { + const bool should_profile = op->should_profile(); + + if (should_profile) { ciMethod* method = op->profiled_method(); assert(method != NULL, "Should have method"); int bci = op->profiled_bci(); @@ -1324,8 +1330,8 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); } Label profile_cast_success, profile_cast_failure; - Label *success_target = op->should_profile() ? &profile_cast_success : success; - Label *failure_target = op->should_profile() ? &profile_cast_failure : failure; + Label *success_target = should_profile ? &profile_cast_success : success; + Label *failure_target = should_profile ? &profile_cast_failure : failure; if (obj == k_RInfo) { k_RInfo = dst; @@ -1341,7 +1347,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L assert_different_registers(obj, k_RInfo, klass_RInfo); - if (op->should_profile()) { + if (should_profile) { Label not_null; __ cbnz(obj, not_null); // Object is null; update MDO and exit @@ -1413,7 +1419,7 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L // successful cast, fall through to profile or jump } } - if (op->should_profile()) { + if (should_profile) { Register mdo = klass_RInfo, recv = k_RInfo; __ bind(profile_cast_success); __ mov_metadata(mdo, md->constant_encoding()); @@ -1438,6 +1444,8 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { + const bool should_profile = op->should_profile(); + LIR_Code code = op->code(); if (code == lir_store_check) { Register value = op->object()->as_register(); @@ -1452,7 +1460,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { ciMethodData* md; ciProfileData* data; - if (op->should_profile()) { + if (should_profile) { ciMethod* method = op->profiled_method(); assert(method != NULL, "Should have method"); int bci = op->profiled_bci(); @@ -1463,10 +1471,10 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { assert(data->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); } Label profile_cast_success, profile_cast_failure, done; - Label *success_target = op->should_profile() ? &profile_cast_success : &done; - Label *failure_target = op->should_profile() ? &profile_cast_failure : stub->entry(); + Label *success_target = should_profile ? &profile_cast_success : &done; + Label *failure_target = should_profile ? &profile_cast_failure : stub->entry(); - if (op->should_profile()) { + if (should_profile) { Label not_null; __ cbnz(value, not_null); // Object is null; update MDO and exit @@ -1502,7 +1510,7 @@ void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { __ cbzw(k_RInfo, *failure_target); // fall through to the success case - if (op->should_profile()) { + if (should_profile) { Register mdo = klass_RInfo, recv = k_RInfo; __ bind(profile_cast_success); __ mov_metadata(mdo, md->constant_encoding()); @@ -1621,9 +1629,10 @@ void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, L case lir_cond_lessEqual: acond = Assembler::LE; ncond = Assembler::GT; break; case lir_cond_greaterEqual: acond = Assembler::GE; ncond = Assembler::LT; break; case lir_cond_greater: acond = Assembler::GT; ncond = Assembler::LE; break; - case lir_cond_belowEqual: Unimplemented(); break; - case lir_cond_aboveEqual: Unimplemented(); break; + case lir_cond_belowEqual: + case lir_cond_aboveEqual: default: ShouldNotReachHere(); + acond = Assembler::EQ; ncond = Assembler::NE; // unreachable } assert(result->is_single_cpu() || result->is_double_cpu(), @@ -1724,6 +1733,7 @@ void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr break; default: ShouldNotReachHere(); + c = 0; // unreachable break; } @@ -1926,6 +1936,7 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, break; default: ShouldNotReachHere(); + imm = 0; // unreachable break; } @@ -3123,6 +3134,9 @@ void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr break; default: ShouldNotReachHere(); + lda = &MacroAssembler::ldaxr; + add = &MacroAssembler::add; + stl = &MacroAssembler::stlxr; // unreachable } switch (code) { diff --git a/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp index 21c7cfc93ff..191c4e45571 100644 --- a/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/c1_LIRGenerator_aarch64.cpp @@ -238,6 +238,7 @@ LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) { } } else { ShouldNotReachHere(); + r = NULL; // unreachable } return r; } diff --git a/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp index 96a967fb961..e29c1ec0e22 100644 --- a/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/interpreter_aarch64.cpp @@ -230,6 +230,7 @@ void InterpreterGenerator::generate_transcendental_entry(AbstractInterpreter::Me break; default: ShouldNotReachHere(); + fn = NULL; // unreachable } const int gpargs = 0, rtype = 3; __ mov(rscratch1, fn); diff --git a/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp index 14c8367f371..b2f21031f18 100644 --- a/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/jniFastGetField_aarch64.cpp @@ -61,6 +61,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { case T_FLOAT: name = "jni_fast_GetFloatField"; break; case T_DOUBLE: name = "jni_fast_GetDoubleField"; break; default: ShouldNotReachHere(); + name = NULL; // unreachable } ResourceMark rm; BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE); @@ -125,6 +126,7 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break; case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break; default: ShouldNotReachHere(); + slow_case_addr = NULL; // unreachable } { From e699dcb655ccf905eb6bc47ca0c5807197edc06e Mon Sep 17 00:00:00 2001 From: Dmitrij Pochepko Date: Wed, 16 Dec 2015 18:38:02 +0300 Subject: [PATCH 060/215] 8141351: Create tests for direct invoke instructions testing Tests for invoke* instructions Reviewed-by: twisti --- hotspot/make/test/JtregNative.gmk | 1 + .../compiler/calls/common/CallInterface.java | 35 +++ .../test/compiler/calls/common/CallsBase.java | 217 ++++++++++++++++++ .../compiler/calls/common/InvokeDynamic.java | 99 ++++++++ .../calls/common/InvokeDynamicPatcher.java | 171 ++++++++++++++ .../calls/common/InvokeInterface.java | 84 +++++++ .../compiler/calls/common/InvokeSpecial.java | 80 +++++++ .../compiler/calls/common/InvokeStatic.java | 91 ++++++++ .../compiler/calls/common/InvokeVirtual.java | 81 +++++++ .../compiler/calls/common/libCallsNative.c | 148 ++++++++++++ .../CompiledInvokeDynamic2CompiledTest.java | 45 ++++ ...CompiledInvokeDynamic2InterpretedTest.java | 39 ++++ .../CompiledInvokeDynamic2NativeTest.java | 39 ++++ .../CompiledInvokeInterface2CompiledTest.java | 43 ++++ ...mpiledInvokeInterface2InterpretedTest.java | 37 +++ .../CompiledInvokeInterface2NativeTest.java | 37 +++ .../CompiledInvokeSpecial2CompiledTest.java | 43 ++++ ...CompiledInvokeSpecial2InterpretedTest.java | 37 +++ .../CompiledInvokeSpecial2NativeTest.java | 37 +++ .../CompiledInvokeStatic2CompiledTest.java | 43 ++++ .../CompiledInvokeStatic2InterpretedTest.java | 37 +++ .../CompiledInvokeStatic2NativeTest.java | 37 +++ .../CompiledInvokeVirtual2CompiledTest.java | 43 ++++ ...CompiledInvokeVirtual2InterpretedTest.java | 37 +++ .../CompiledInvokeVirtual2NativeTest.java | 37 +++ ...InterpretedInvokeDynamic2CompiledTest.java | 39 ++++ ...erpretedInvokeDynamic2InterpretedTest.java | 36 +++ .../InterpretedInvokeDynamic2NativeTest.java | 36 +++ ...terpretedInvokeInterface2CompiledTest.java | 37 +++ ...pretedInvokeInterface2InterpretedTest.java | 34 +++ ...InterpretedInvokeInterface2NativeTest.java | 34 +++ ...InterpretedInvokeSpecial2CompiledTest.java | 37 +++ ...erpretedInvokeSpecial2InterpretedTest.java | 34 +++ .../InterpretedInvokeSpecial2NativeTest.java | 34 +++ .../InterpretedInvokeStatic2CompiledTest.java | 37 +++ ...terpretedInvokeStatic2InterpretedTest.java | 34 +++ .../InterpretedInvokeStatic2NativeTest.java | 34 +++ ...InterpretedInvokeVirtual2CompiledTest.java | 37 +++ ...erpretedInvokeVirtual2InterpretedTest.java | 34 +++ .../InterpretedInvokeVirtual2NativeTest.java | 34 +++ .../NativeInvokeSpecial2CompiledTest.java | 37 +++ .../NativeInvokeSpecial2InterpretedTest.java | 34 +++ .../NativeInvokeSpecial2NativeTest.java | 34 +++ .../NativeInvokeStatic2CompiledTest.java | 37 +++ .../NativeInvokeStatic2InterpretedTest.java | 34 +++ .../NativeInvokeStatic2NativeTest.java | 34 +++ .../NativeInvokeVirtual2CompiledTest.java | 37 +++ .../NativeInvokeVirtual2InterpretedTest.java | 34 +++ .../NativeInvokeVirtual2NativeTest.java | 34 +++ 49 files changed, 2444 insertions(+) create mode 100644 hotspot/test/compiler/calls/common/CallInterface.java create mode 100644 hotspot/test/compiler/calls/common/CallsBase.java create mode 100644 hotspot/test/compiler/calls/common/InvokeDynamic.java create mode 100644 hotspot/test/compiler/calls/common/InvokeDynamicPatcher.java create mode 100644 hotspot/test/compiler/calls/common/InvokeInterface.java create mode 100644 hotspot/test/compiler/calls/common/InvokeSpecial.java create mode 100644 hotspot/test/compiler/calls/common/InvokeStatic.java create mode 100644 hotspot/test/compiler/calls/common/InvokeVirtual.java create mode 100644 hotspot/test/compiler/calls/common/libCallsNative.c create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2CompiledTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2InterpretedTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2NativeTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2CompiledTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2InterpretedTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2NativeTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2CompiledTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2InterpretedTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2NativeTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2CompiledTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2InterpretedTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2NativeTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2CompiledTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2InterpretedTest.java create mode 100644 hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2NativeTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2CompiledTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2InterpretedTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2NativeTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2CompiledTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2InterpretedTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2NativeTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2CompiledTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2InterpretedTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2NativeTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2CompiledTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2InterpretedTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2NativeTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2CompiledTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2InterpretedTest.java create mode 100644 hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2NativeTest.java create mode 100644 hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2CompiledTest.java create mode 100644 hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2InterpretedTest.java create mode 100644 hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2NativeTest.java create mode 100644 hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2CompiledTest.java create mode 100644 hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2InterpretedTest.java create mode 100644 hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2NativeTest.java create mode 100644 hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2CompiledTest.java create mode 100644 hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2InterpretedTest.java create mode 100644 hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2NativeTest.java diff --git a/hotspot/make/test/JtregNative.gmk b/hotspot/make/test/JtregNative.gmk index d49a03757e7..109c04d37fb 100644 --- a/hotspot/make/test/JtregNative.gmk +++ b/hotspot/make/test/JtregNative.gmk @@ -47,6 +47,7 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \ $(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \ $(HOTSPOT_TOPDIR)/test/runtime/SameObject \ $(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \ + $(HOTSPOT_TOPDIR)/test/compiler/calls \ # # Add conditional directories here when needed. diff --git a/hotspot/test/compiler/calls/common/CallInterface.java b/hotspot/test/compiler/calls/common/CallInterface.java new file mode 100644 index 00000000000..84b7b075150 --- /dev/null +++ b/hotspot/test/compiler/calls/common/CallInterface.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + +package compiler.calls.common; + +/** + * A test interface used for InvokeInterface + */ +public interface CallInterface { + public boolean callee(int param1, long param2, float param3, double param4, + String param5); + + public boolean calleeNative(int param1, long param2, float param3, + double param4, String param5); +} diff --git a/hotspot/test/compiler/calls/common/CallsBase.java b/hotspot/test/compiler/calls/common/CallsBase.java new file mode 100644 index 00000000000..f6a9ad93f23 --- /dev/null +++ b/hotspot/test/compiler/calls/common/CallsBase.java @@ -0,0 +1,217 @@ +/* + * 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. + */ + +package compiler.calls.common; + +import compiler.testlibrary.CompilerUtils; +import java.lang.reflect.Method; +import java.util.Arrays; +import jdk.test.lib.Asserts; +import sun.hotspot.WhiteBox; + +/** + * A common class for Invoke* classes + */ +public abstract class CallsBase { + public static final String CALL_ERR_MSG = "Call insuccessfull"; + protected final Method calleeMethod; + protected final Method callerMethod; + protected final WhiteBox wb = WhiteBox.getWhiteBox(); + protected int compileCallee = -1; + protected int compileCaller = -1; + protected boolean nativeCallee = false; + protected boolean nativeCaller = false; + protected boolean calleeVisited = false; + protected boolean checkCallerCompilationLevel; + protected boolean checkCalleeCompilationLevel; + protected int expectedCallerCompilationLevel; + protected int expectedCalleeCompilationLevel; + + protected CallsBase() { + try { + callerMethod = getClass().getDeclaredMethod("caller"); + calleeMethod = getClass().getDeclaredMethod("callee", + getCalleeParametersTypes()); + wb.testSetDontInlineMethod(callerMethod, /* dontinline= */ true); + wb.testSetDontInlineMethod(calleeMethod, /* dontinline= */ true); + } catch (NoSuchMethodException e) { + throw new Error("TEST BUG: can't find test method", e); + } + } + + /** + * Provides callee parameters types to search method + * @return array of types + */ + protected Class[] getCalleeParametersTypes() { + return new Class[] {int.class, long.class, float.class, + double.class, String.class}; + } + + /** + * Loads native library(libCallsNative.so) + */ + protected static void loadNativeLibrary() { + System.loadLibrary("CallsNative"); + } + + /** + * Checks if requested compilation levels are inside of current vm capabilities + * @return true if vm is capable of requested compilation levels + */ + protected final boolean compilationLevelsSupported() { + int[] compLevels = CompilerUtils.getAvailableCompilationLevels(); + boolean callerCompLevelSupported = compileCaller > 0 + && Arrays.stream(compLevels) + .filter(elem -> elem == compileCaller) + .findAny() + .isPresent(); + boolean calleeCompLevelSupported = compileCallee > 0 + && Arrays.stream(compLevels) + .filter(elem -> elem == compileCallee) + .findAny() + .isPresent(); + return callerCompLevelSupported && calleeCompLevelSupported; + } + + /** + * Parse test arguments + * @param args test arguments + */ + protected final void parseArgs(String args[]) { + for (int i = 0; i < args.length; i++) { + switch (args[i]) { + case "-nativeCallee": + nativeCallee = true; + break; + case "-nativeCaller": + nativeCaller = true; + break; + case "-compileCallee": + compileCallee = Integer.parseInt(args[++i]); + break; + case "-compileCaller": + compileCaller = Integer.parseInt(args[++i]); + break; + case "-checkCallerCompileLevel": + checkCallerCompilationLevel = true; + expectedCallerCompilationLevel = Integer.parseInt(args[++i]); + break; + case "-checkCalleeCompileLevel": + checkCalleeCompilationLevel = true; + expectedCalleeCompilationLevel = Integer.parseInt(args[++i]); + break; + default: + throw new Error("Can't parse test parameter:" + args[i]); + } + } + } + + /** + * Run basic logic of a test by doing compile + * action(if needed). An arguments can be -compileCallee + * $calleeCompilationLevel and/or -compileCaller $callerCompilationLevel + * and/or -nativeCaller and/or -nativeCallee to indicate that native methods + * for caller/callee should be used + * @param args test args + */ + protected final void runTest(String args[]) { + parseArgs(args); + if (compilationLevelsSupported()) { + if (nativeCaller || nativeCallee) { + CallsBase.loadNativeLibrary(); + } + Object lock = getLockObject(); + Asserts.assertNotNull(lock, "Lock object is null"); + /* a following lock is needed in case several instances of this + test are launched in same vm */ + synchronized (lock) { + if (compileCaller > 0 || compileCallee > 0) { + caller(); // call once to have everything loaded + calleeVisited = false; // reset state + } + // compile with requested level if needed + if (compileCallee > 0) { + compileMethod(calleeMethod, compileCallee); + } + if (checkCalleeCompilationLevel) { + Asserts.assertEQ(expectedCalleeCompilationLevel, + wb.getMethodCompilationLevel(calleeMethod), + "Unexpected callee compilation level"); + } + if (compileCaller > 0) { + compileMethod(callerMethod, compileCaller); + } + if (checkCallerCompilationLevel) { + Asserts.assertEQ(expectedCallerCompilationLevel, + wb.getMethodCompilationLevel(callerMethod), + "Unexpected caller compilation level"); + } + // do calling work + if (nativeCaller) { + callerNative(); + } else { + caller(); + } + } + } else { + System.out.println("WARNING: Requested compilation levels are " + + "out of current vm capabilities. Skipping."); + } + } + + /** + * A method to compile another method, searching it by name in current class + * @param method a method to compile + * @param compLevel a compilation level + */ + protected final void compileMethod(Method method, int compLevel) { + wb.deoptimizeMethod(method); + Asserts.assertTrue(wb.isMethodCompilable(method, compLevel)); + wb.enqueueMethodForCompilation(method, compLevel); + } + + /* + * @return Object to lock on during execution + */ + + protected abstract Object getLockObject(); + + protected abstract void caller(); + + protected abstract void callerNative(); + + /** + * A method checking values. Should be used to verify if all parameters are + * passed as expected. Parameter N should have a value indicating number "N" + * in respective type representation. + */ + public static void checkValues(int param1, long param2, float param3, + double param4, String param5) { + Asserts.assertEQ(param1, 1); + Asserts.assertEQ(param2, 2L); + Asserts.assertEQ(param3, 3.0f); + Asserts.assertEQ(param4, 4.0d); + Asserts.assertEQ(param5, "5"); + } +} diff --git a/hotspot/test/compiler/calls/common/InvokeDynamic.java b/hotspot/test/compiler/calls/common/InvokeDynamic.java new file mode 100644 index 00000000000..018a2992e80 --- /dev/null +++ b/hotspot/test/compiler/calls/common/InvokeDynamic.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package compiler.calls.common; + +import java.lang.invoke.CallSite; +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +/** + * A test class checking InvokeDynamic instruction. + * This is not quite "ready-to-use" class, since javac can't generate indy + * directly(only as part of lambda init) so, this class bytecode should be + * patched with method "caller" which uses indy. Other methods can be written in + * java for easier support and readability. + */ + +public class InvokeDynamic extends CallsBase { + private static final Object LOCK = new Object(); + + public static void main(String args[]) { + new InvokeDynamic().runTest(args); + } + + /** + * Caller method to call "callee" method. Must be overwritten with InvokeDynamicPatcher + */ + @Override + public void caller() { + } + + /** + * A bootstrap method for invokedynamic + * @param lookup a lookup object + * @param methodName methodName + * @param type method type + * @return CallSite for method + */ + public static CallSite bootstrapMethod(MethodHandles.Lookup lookup, + String methodName, MethodType type) throws IllegalAccessException, + NoSuchMethodException { + MethodType mtype = MethodType.methodType(boolean.class, + new Class[]{int.class, long.class, float.class, + double.class, String.class}); + return new ConstantCallSite(lookup.findVirtual(lookup.lookupClass(), + methodName, mtype)); + } + + /** + * A callee method, assumed to be called by "caller" + */ + public boolean callee(int param1, long param2, float param3, double param4, + String param5) { + calleeVisited = true; + CallsBase.checkValues(param1, param2, param3, param4, param5); + return true; + } + + /** + * A native callee method, assumed to be called by "caller" + */ + public native boolean calleeNative(int param1, long param2, float param3, + double param4, String param5); + + /** + * Returns object to lock execution on + * @return lock object + */ + @Override + protected Object getLockObject() { + return LOCK; + } + + @Override + protected void callerNative() { + throw new Error("No native call for invokedynamic"); + } +} diff --git a/hotspot/test/compiler/calls/common/InvokeDynamicPatcher.java b/hotspot/test/compiler/calls/common/InvokeDynamicPatcher.java new file mode 100644 index 00000000000..644f0a21b6e --- /dev/null +++ b/hotspot/test/compiler/calls/common/InvokeDynamicPatcher.java @@ -0,0 +1,171 @@ +/* + * 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. + */ + +package compiler.calls.common; + +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * A class which patch InvokeDynamic class bytecode with invokydynamic + instruction, rewriting "caller" method to call "callee" method using + invokedynamic + */ +public class InvokeDynamicPatcher extends ClassVisitor { + + private static final String CLASS = InvokeDynamic.class.getName() + .replace('.', '/'); + private static final String CALLER_METHOD_NAME = "caller"; + private static final String CALLEE_METHOD_NAME = "callee"; + private static final String NATIVE_CALLEE_METHOD_NAME = "calleeNative"; + private static final String BOOTSTRAP_METHOD_NAME = "bootstrapMethod"; + private static final String CALL_NATIVE_FIELD = "nativeCallee"; + private static final String CALL_NATIVE_FIELD_DESC = "Z"; + private static final String CALLEE_METHOD_DESC + = "(L" + CLASS + ";IJFDLjava/lang/String;)Z"; + private static final String ASSERTTRUE_METHOD_DESC + = "(ZLjava/lang/String;)V"; + private static final String ASSERTS_CLASS = "jdk/test/lib/Asserts"; + private static final String ASSERTTRUE_METHOD_NAME = "assertTrue"; + + public static void main(String args[]) { + ClassReader cr; + Path filePath; + try { + filePath = Paths.get(InvokeDynamic.class.getProtectionDomain().getCodeSource() + .getLocation().toURI()).resolve(CLASS + ".class"); + } catch (URISyntaxException ex) { + throw new Error("TESTBUG: Can't get code source" + ex, ex); + } + try (FileInputStream fis = new FileInputStream(filePath.toFile())) { + cr = new ClassReader(fis); + } catch (IOException e) { + throw new Error("Error reading file", e); + } + ClassWriter cw = new ClassWriter(cr, + ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + cr.accept(new InvokeDynamicPatcher(Opcodes.ASM5, cw), 0); + try { + Files.write(filePath, cw.toByteArray(), + StandardOpenOption.WRITE); + } catch (IOException e) { + throw new Error(e); + } + } + + public InvokeDynamicPatcher(int api, ClassWriter cw) { + super(api, cw); + } + + @Override + public MethodVisitor visitMethod(final int access, final String name, + final String desc, final String signature, + final String[] exceptions) { + /* a code generate looks like + * 0: aload_0 + * 1: ldc #125 // int 1 + * 3: ldc2_w #126 // long 2l + * 6: ldc #128 // float 3.0f + * 8: ldc2_w #129 // double 4.0d + * 11: ldc #132 // String 5 + * 13: aload_0 + * 14: getfield #135 // Field nativeCallee:Z + * 17: ifeq 28 + * 20: invokedynamic #181, 0 // InvokeDynamic #1:calleeNative:(Lcompiler/calls/common/InvokeDynamic;IJFDLjava/lang/String;)Z + * 25: goto 33 + * 28: invokedynamic #183, 0 // InvokeDynamic #1:callee:(Lcompiler/calls/common/InvokeDynamic;IJFDLjava/lang/String;)Z + * 33: ldc #185 // String Call insuccessfull + * 35: invokestatic #191 // Method jdk/test/lib/Asserts.assertTrue:(ZLjava/lang/String;)V + * 38: return + * + * or, using java-like pseudo-code + * if (this.nativeCallee == false) { + * invokedynamic-call-return-value = invokedynamic-of-callee + * } else { + * invokedynamic-call-return-value = invokedynamic-of-nativeCallee + * } + * Asserts.assertTrue(invokedynamic-call-return-value, error-message); + * return; + */ + if (name.equals(CALLER_METHOD_NAME)) { + MethodVisitor mv = cv.visitMethod(access, name, desc, + signature, exceptions); + Label nonNativeLabel = new Label(); + Label checkLabel = new Label(); + MethodType mtype = MethodType.methodType(CallSite.class, + MethodHandles.Lookup.class, String.class, MethodType.class); + Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, CLASS, + BOOTSTRAP_METHOD_NAME, mtype.toMethodDescriptorString()); + mv.visitCode(); + // push callee parameters onto stack + mv.visitVarInsn(Opcodes.ALOAD, 0);//push "this" + mv.visitLdcInsn(1); + mv.visitLdcInsn(2L); + mv.visitLdcInsn(3.0f); + mv.visitLdcInsn(4.0d); + mv.visitLdcInsn("5"); + // params loaded. let's decide what method to call + mv.visitVarInsn(Opcodes.ALOAD, 0); // push "this" + // get nativeCallee field + mv.visitFieldInsn(Opcodes.GETFIELD, CLASS, CALL_NATIVE_FIELD, + CALL_NATIVE_FIELD_DESC); + // if nativeCallee == false goto nonNativeLabel + mv.visitJumpInsn(Opcodes.IFEQ, nonNativeLabel); + // invokedynamic nativeCalleeMethod using bootstrap method + mv.visitInvokeDynamicInsn(NATIVE_CALLEE_METHOD_NAME, + CALLEE_METHOD_DESC, bootstrap); + // goto checkLabel + mv.visitJumpInsn(Opcodes.GOTO, checkLabel); + // label: nonNativeLabel + mv.visitLabel(nonNativeLabel); + // invokedynamic calleeMethod using bootstrap method + mv.visitInvokeDynamicInsn(CALLEE_METHOD_NAME, CALLEE_METHOD_DESC, + bootstrap); + mv.visitLabel(checkLabel); + mv.visitLdcInsn(CallsBase.CALL_ERR_MSG); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, ASSERTS_CLASS, + ASSERTTRUE_METHOD_NAME, ASSERTTRUE_METHOD_DESC, false); + // label: return + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + return null; + } + return super.visitMethod(access, name, desc, signature, exceptions); + } +} diff --git a/hotspot/test/compiler/calls/common/InvokeInterface.java b/hotspot/test/compiler/calls/common/InvokeInterface.java new file mode 100644 index 00000000000..7ae77d5c4ee --- /dev/null +++ b/hotspot/test/compiler/calls/common/InvokeInterface.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package compiler.calls.common; + +import jdk.test.lib.Asserts; + +/** + * A test class checking InvokeInterface instruction + */ +public class InvokeInterface extends CallsBase implements CallInterface { + private static final Object LOCK = new Object(); + + public static void main(String args[]) { + new InvokeInterface().runTest(args); + } + + /** + * A caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public void caller() { + // cast to CallInterface to force invokeinterface usage + if (nativeCallee) { + Asserts.assertTrue(((CallInterface) this) + .calleeNative(1, 2L, 3.0f, 4.0d, "5"), CALL_ERR_MSG); + } else { + Asserts.assertTrue(((CallInterface) this) + .callee(1, 2L, 3.0f, 4.0d, "5"), CALL_ERR_MSG); + } + } + + /** + * A callee method, assumed to be called by "caller"/"callerNative" + */ + @Override + public boolean callee(int param1, long param2, float param3, double param4, + String param5) { + calleeVisited = true; + CallsBase.checkValues(param1, param2, param3, param4, param5); + return true; + } + + /** + * A native callee method, assumed to be called by "caller"/"callerNative" + */ + @Override + public native boolean calleeNative(int param1, long param2, float param3, + double param4, String param5); + + /** + * Returns object to lock execution on + * @return lock object + */ + @Override + protected Object getLockObject() { + return LOCK; + } + + @Override + protected void callerNative() { + throw new Error("No native call for invokeinterface"); + } +} diff --git a/hotspot/test/compiler/calls/common/InvokeSpecial.java b/hotspot/test/compiler/calls/common/InvokeSpecial.java new file mode 100644 index 00000000000..1eb34873a83 --- /dev/null +++ b/hotspot/test/compiler/calls/common/InvokeSpecial.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package compiler.calls.common; + +import jdk.test.lib.Asserts; + +/** + * A test class checking InvokeSpecial instruction + */ +public class InvokeSpecial extends CallsBase { + private static final Object LOCK = new Object(); + + public static void main(String args[]) { + new InvokeSpecial().runTest(args); + } + + /** + * A native caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public native void callerNative(); + + /** + * A caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public void caller() { + if (nativeCallee) { + Asserts.assertTrue(calleeNative(1, 2L, 3.0f, 4.0d, "5"), CALL_ERR_MSG); + } else { + Asserts.assertTrue(callee(1, 2L, 3.0f, 4.0d, "5"), CALL_ERR_MSG); + } + } + + /** + * A callee method, assumed to be called by "caller"/"callerNative" + */ + private boolean callee(int param1, long param2, float param3, double param4, + String param5) { + calleeVisited = true; + CallsBase.checkValues(param1, param2, param3, param4, param5); + return true; + } + + /** + * A native callee method, assumed to be called by "caller"/"callerNative" + */ + public native boolean calleeNative(int param1, long param2, float param3, + double param4, String param5); + + /** + * Returns object to lock execution on + * @return lock object + */ + @Override + protected Object getLockObject() { + return LOCK; + } +} diff --git a/hotspot/test/compiler/calls/common/InvokeStatic.java b/hotspot/test/compiler/calls/common/InvokeStatic.java new file mode 100644 index 00000000000..18abcae7327 --- /dev/null +++ b/hotspot/test/compiler/calls/common/InvokeStatic.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package compiler.calls.common; + +import jdk.test.lib.Asserts; + +/** + * A test class checking InvokeStatic instruction + */ +public class InvokeStatic extends CallsBase { + private static final Object LOCK = new Object(); + + public static void main(String args[]) { + new InvokeStatic().runTest(args); + } + + /** + * A native caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public native void callerNative(); + + /** + * A caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public void caller() { + if (nativeCallee) { + Asserts.assertTrue(calleeNative(this, 1, 2L, 3.0f, 4.0d, "5"), + CALL_ERR_MSG); + } else { + Asserts.assertTrue(callee(this, 1, 2L, 3.0f, 4.0d, "5"), + CALL_ERR_MSG); + } + } + + /** + * A callee method, assumed to be called by "caller"/"callerNative" + */ + public static boolean callee(InvokeStatic instance, int param1, + long param2, float param3, double param4, String param5) { + instance.calleeVisited = true; + CallsBase.checkValues(param1, param2, param3, param4, param5); + return true; + } + + /** + * A native callee method, assumed to be called by "caller"/"callerNative" + */ + public static native boolean calleeNative(InvokeStatic instance, + int param1, long param2, float param3, double param4, String param5); + + /** + * Returns object to lock execution on + * @return lock object + */ + @Override + protected Object getLockObject() { + return LOCK; + } + + /** + * Provides callee parameters types to search method + * @return array of types + */ + protected Class[] getCalleeParametersTypes() { + return new Class[]{InvokeStatic.class, int.class, long.class, + float.class, double.class, String.class}; + } +} diff --git a/hotspot/test/compiler/calls/common/InvokeVirtual.java b/hotspot/test/compiler/calls/common/InvokeVirtual.java new file mode 100644 index 00000000000..6443fd63bc3 --- /dev/null +++ b/hotspot/test/compiler/calls/common/InvokeVirtual.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package compiler.calls.common; + +import jdk.test.lib.Asserts; + +/** + * A test class checking InvokeVirtual instruction + */ + +public class InvokeVirtual extends CallsBase { + private static final Object LOCK = new Object(); + + public static void main(String args[]) { + new InvokeVirtual().runTest(args); + } + + /** + * A native caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public native void callerNative(); + + /** + * A caller method, assumed to called "callee"/"calleeNative" + */ + @Override + public void caller() { + if (nativeCallee) { + Asserts.assertTrue(calleeNative(1, 2L, 3.0f, 4.0d, "5"), CALL_ERR_MSG); + } else { + Asserts.assertTrue(callee(1, 2L, 3.0f, 4.0d, "5"), CALL_ERR_MSG); + } + } + + /** + * A callee method, assumed to be called by "caller"/"callerNative" + */ + public boolean callee(int param1, long param2, float param3, double param4, + String param5) { + calleeVisited = true; + CallsBase.checkValues(param1, param2, param3, param4, param5); + return true; + } + + /** + * A native callee method, assumed to be called by "caller"/"callerNative" + */ + public native boolean calleeNative(int param1, long param2, float param3, + double param4, String param5); + + /** + * Returns object to lock execution on + * @return lock object + */ + @Override + protected Object getLockObject() { + return LOCK; + } +} diff --git a/hotspot/test/compiler/calls/common/libCallsNative.c b/hotspot/test/compiler/calls/common/libCallsNative.c new file mode 100644 index 00000000000..aacaacc3de1 --- /dev/null +++ b/hotspot/test/compiler/calls/common/libCallsNative.c @@ -0,0 +1,148 @@ +/* + * 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 + +#include "jni.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define METHOD_SIGNATURE "(IJFDLjava/lang/String;)Z" +#define STATIC_CALLEE_SIGNATURE "(Lcompiler/calls/common/InvokeStatic;IJFDLjava/lang/String;)Z" +#define BASE_CLASS "compiler/calls/common/CallsBase" + +#define CHECK_EXCEPTIONS if ((*env)->ExceptionCheck(env)) return +#define CHECK_EXCEPTIONS_FALSE if ((*env)->ExceptionCheck(env)) return JNI_FALSE + +#define IS_STATIC 1 +#define NOT_STATIC 0 + +jboolean doCalleeWork(JNIEnv *env, jobject self, jint param1, jlong param2, + jfloat param3, jdouble param4, jstring param5) { + jclass cls = (*env)->GetObjectClass(env, self); + jfieldID calleeVisitedID = (*env)->GetFieldID(env, cls, "calleeVisited", "Z"); + jclass CheckCallsBaseClass; + jmethodID checkValuesID; + CHECK_EXCEPTIONS_FALSE; + (*env)->SetBooleanField(env, self, calleeVisitedID, JNI_TRUE); + CHECK_EXCEPTIONS_FALSE; + CheckCallsBaseClass = (*env)->FindClass(env, BASE_CLASS); + CHECK_EXCEPTIONS_FALSE; + checkValuesID = (*env)->GetStaticMethodID(env, CheckCallsBaseClass, + "checkValues", "(IJFDLjava/lang/String;)V"); + CHECK_EXCEPTIONS_FALSE; + (*env)->CallStaticVoidMethod(env, CheckCallsBaseClass, checkValuesID, + param1, param2, param3, param4, param5); + return JNI_TRUE; +} + +JNIEXPORT jboolean JNICALL Java_compiler_calls_common_InvokeDynamic_calleeNative(JNIEnv *env, jobject obj, + jint param1, jlong param2, jfloat param3, jdouble param4, jstring param5) { + return doCalleeWork(env, obj, param1, param2, param3, param4, param5); +} + +JNIEXPORT jboolean JNICALL Java_compiler_calls_common_InvokeInterface_calleeNative(JNIEnv *env, jobject obj, + jint param1, jlong param2, jfloat param3, jdouble param4, jstring param5) { + return doCalleeWork(env, obj, param1, param2, param3, param4, param5); +} + +JNIEXPORT jboolean JNICALL Java_compiler_calls_common_InvokeSpecial_calleeNative(JNIEnv *env, jobject obj, + jint param1, jlong param2, jfloat param3, jdouble param4, jstring param5) { + return doCalleeWork(env, obj, param1, param2, param3, param4, param5); +} + +JNIEXPORT jboolean JNICALL Java_compiler_calls_common_InvokeVirtual_calleeNative(JNIEnv *env, jobject obj, + jint param1, jlong param2, jfloat param3, jdouble param4, jstring param5) { + return doCalleeWork(env, obj, param1, param2, param3, param4, param5); +} + +JNIEXPORT jboolean JNICALL Java_compiler_calls_common_InvokeStatic_calleeNative(JNIEnv *env, jclass obj, + jobject self, jint param1, jlong param2, jfloat param3, jdouble param4, jstring param5) { + return doCalleeWork(env, self, param1, param2, param3, param4, param5); +} + +void doCallerWork(JNIEnv *env, jobject obj, int isStatic) { + jclass cls = (*env)->GetObjectClass(env, obj); + jmethodID calleeMethodID = 0; + jfieldID errorMessageID; + jfieldID nativeCalleeID; + jobject errorMessage; + jmethodID assertTrue; + jboolean callNative; + jclass assertsClass; + jclass baseClass; + jboolean result; + char* methodName; + CHECK_EXCEPTIONS; + nativeCalleeID = (*env)->GetFieldID(env, cls, "nativeCallee", "Z"); + CHECK_EXCEPTIONS; + callNative = (*env)->GetBooleanField(env, obj, nativeCalleeID); + CHECK_EXCEPTIONS; + methodName = (callNative == JNI_TRUE) ? "calleeNative" : "callee"; + if (isStatic) { + calleeMethodID = (*env)->GetStaticMethodID(env, cls, methodName, + STATIC_CALLEE_SIGNATURE); + } else { + calleeMethodID = (*env)->GetMethodID(env, cls, methodName, METHOD_SIGNATURE); + } + CHECK_EXCEPTIONS; + if (isStatic) { + result = (*env)->CallStaticBooleanMethod(env, cls, calleeMethodID, obj, + (jint) 1, (jlong) 2L, (jfloat) 3.0f, (jdouble) 4.0, (*env)->NewStringUTF(env, "5")); + } else { + result = (*env)->CallBooleanMethod(env, obj, calleeMethodID, + (jint) 1, (jlong) 2L, (jfloat) 3.0f, (jdouble) 4.0, (*env)->NewStringUTF(env, "5")); + } + CHECK_EXCEPTIONS; + baseClass = (*env)->FindClass(env, BASE_CLASS); + CHECK_EXCEPTIONS; + errorMessageID = (*env)->GetStaticFieldID(env, baseClass, + "CALL_ERR_MSG", "Ljava/lang/String;"); + CHECK_EXCEPTIONS; + errorMessage = (*env)->GetStaticObjectField(env, baseClass, errorMessageID); + CHECK_EXCEPTIONS; + assertsClass = (*env)->FindClass(env, "jdk/test/lib/Asserts"); + CHECK_EXCEPTIONS; + assertTrue = (*env)->GetStaticMethodID(env, assertsClass, + "assertTrue", "(ZLjava/lang/String;)V"); + (*env)->CallStaticVoidMethod(env, assertsClass, assertTrue, result, + errorMessage); +} + +JNIEXPORT void JNICALL Java_compiler_calls_common_InvokeSpecial_callerNative(JNIEnv *env, jobject obj) { + doCallerWork(env, obj, NOT_STATIC); +} + +JNIEXPORT void JNICALL Java_compiler_calls_common_InvokeVirtual_callerNative(JNIEnv *env, jobject obj) { + doCallerWork(env, obj, NOT_STATIC); +} + +JNIEXPORT void JNICALL Java_compiler_calls_common_InvokeStatic_callerNative(JNIEnv *env, jobject obj) { + doCallerWork(env, obj, IS_STATIC); +} + +#ifdef __cplusplus +} +#endif diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2CompiledTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2CompiledTest.java new file mode 100644 index 00000000000..dd4daef9849 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2CompiledTest.java @@ -0,0 +1,45 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeDynamic + * @build compiler.calls.common.InvokeDynamicPatcher + * @run driver compiler.calls.common.InvokeDynamicPatcher + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeDynamic + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeDynamic + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 4 -checkCalleeCompileLevel 4 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeDynamic + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeDynamic + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from compiled to compiled using InvokeDynamic + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2InterpretedTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2InterpretedTest.java new file mode 100644 index 00000000000..3074acbc1a8 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2InterpretedTest.java @@ -0,0 +1,39 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeDynamic + * @build compiler.calls.common.InvokeDynamicPatcher + * @run driver compiler.calls.common.InvokeDynamicPatcher + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::callee compiler.calls.common.InvokeDynamic + * -compileCaller 1 -checkCallerCompileLevel 1 -checkCalleeCompileLevel 0 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::callee compiler.calls.common.InvokeDynamic + * -compileCaller 4 -checkCallerCompileLevel 4 -checkCalleeCompileLevel 0 + * @summary check calls from compiled to interpreted using InvokeDynamic + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2NativeTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2NativeTest.java new file mode 100644 index 00000000000..b06cbf5c89c --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeDynamic2NativeTest.java @@ -0,0 +1,39 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeDynamic + * @build compiler.calls.common.InvokeDynamicPatcher + * @run driver compiler.calls.common.InvokeDynamicPatcher + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeDynamic + * -compileCaller 1 -checkCallerCompileLevel 1 -nativeCallee + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeDynamic + * -compileCaller 4 -checkCallerCompileLevel 4 -nativeCallee + * @summary check calls from compiled to native using InvokeDynamic + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2CompiledTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2CompiledTest.java new file mode 100644 index 00000000000..fec0fda8aee --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2CompiledTest.java @@ -0,0 +1,43 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeInterface + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeInterface + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeInterface + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 4 -checkCalleeCompileLevel 4 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeInterface + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeInterface + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from compiled to compiled using InvokeInterface + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2InterpretedTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2InterpretedTest.java new file mode 100644 index 00000000000..2baf4e7caa8 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2InterpretedTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeInterface + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::callee compiler.calls.common.InvokeInterface + * -compileCaller 1 -checkCallerCompileLevel 1 -checkCalleeCompileLevel 0 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::callee compiler.calls.common.InvokeInterface + * -compileCaller 4 -checkCallerCompileLevel 4 -checkCalleeCompileLevel 0 + * @summary check calls from compiled to interpreted using InvokeInterface + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2NativeTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2NativeTest.java new file mode 100644 index 00000000000..ec394a10f93 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeInterface2NativeTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeInterface + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeInterface + * -compileCaller 1 -checkCallerCompileLevel 1 -nativeCallee + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeInterface + * -compileCaller 4 -checkCallerCompileLevel 4 -nativeCallee + * @summary check calls from compiled to native using InvokeInterface + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2CompiledTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2CompiledTest.java new file mode 100644 index 00000000000..5d659f5bbef --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2CompiledTest.java @@ -0,0 +1,43 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 4 -checkCalleeCompileLevel 4 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from compiled to compiled using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2InterpretedTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2InterpretedTest.java new file mode 100644 index 00000000000..1a6c6c9ec17 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2InterpretedTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::callee compiler.calls.common.InvokeSpecial + * -compileCaller 1 -checkCallerCompileLevel 1 -checkCalleeCompileLevel 0 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::callee compiler.calls.common.InvokeSpecial + * -compileCaller 4 -checkCallerCompileLevel 4 -checkCalleeCompileLevel 0 + * @summary check calls from compiled to interpreted using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2NativeTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2NativeTest.java new file mode 100644 index 00000000000..e1b64749d22 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeSpecial2NativeTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -compileCaller 1 -checkCallerCompileLevel 1 -nativeCallee + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -compileCaller 4 -checkCallerCompileLevel 4 -nativeCallee + * @summary check calls from compiled to native using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2CompiledTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2CompiledTest.java new file mode 100644 index 00000000000..f31ef6ba9ff --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2CompiledTest.java @@ -0,0 +1,43 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 4 -checkCalleeCompileLevel 4 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from compiled to compiled using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2InterpretedTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2InterpretedTest.java new file mode 100644 index 00000000000..8a8b8565a05 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2InterpretedTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::callee compiler.calls.common.InvokeStatic + * -compileCaller 1 -checkCallerCompileLevel 1 -checkCalleeCompileLevel 0 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::callee compiler.calls.common.InvokeStatic + * -compileCaller 4 -checkCallerCompileLevel 4 -checkCalleeCompileLevel 0 + * @summary check calls from compiled to interpreted using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2NativeTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2NativeTest.java new file mode 100644 index 00000000000..955a727f00b --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeStatic2NativeTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -compileCaller 1 -checkCallerCompileLevel 1 -nativeCallee + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -compileCaller 4 -checkCallerCompileLevel 4 -nativeCallee + * @summary check calls from compiled to native using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2CompiledTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2CompiledTest.java new file mode 100644 index 00000000000..53fb39ac117 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2CompiledTest.java @@ -0,0 +1,43 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -compileCaller 1 -checkCallerCompileLevel 1 -compileCallee 4 -checkCalleeCompileLevel 4 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -compileCaller 4 -checkCallerCompileLevel 4 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from compiled to compiled using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2InterpretedTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2InterpretedTest.java new file mode 100644 index 00000000000..d875be780df --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2InterpretedTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::callee compiler.calls.common.InvokeVirtual + * -compileCaller 1 -checkCallerCompileLevel 1 -checkCalleeCompileLevel 0 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::callee compiler.calls.common.InvokeVirtual + * -compileCaller 4 -checkCallerCompileLevel 4 -checkCalleeCompileLevel 0 + * @summary check calls from compiled to interpreted using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2NativeTest.java b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2NativeTest.java new file mode 100644 index 00000000000..0f69bb50cf4 --- /dev/null +++ b/hotspot/test/compiler/calls/fromCompiled/CompiledInvokeVirtual2NativeTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -compileCaller 1 -checkCallerCompileLevel 1 -nativeCallee + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -compileCaller 4 -checkCallerCompileLevel 4 -nativeCallee + * @summary check calls from compiled to native using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2CompiledTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2CompiledTest.java new file mode 100644 index 00000000000..28b38025db6 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2CompiledTest.java @@ -0,0 +1,39 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeDynamic + * @build compiler.calls.common.InvokeDynamicPatcher + * @run driver compiler.calls.common.InvokeDynamicPatcher + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::caller -Xbatch compiler.calls.common.InvokeDynamic + * -checkCallerCompileLevel 0 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::caller -Xbatch compiler.calls.common.InvokeDynamic + * -checkCallerCompileLevel 0 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from interpreted to compiled using InvokeDynamic + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2InterpretedTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2InterpretedTest.java new file mode 100644 index 00000000000..3359e8104be --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2InterpretedTest.java @@ -0,0 +1,36 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeDynamic + * @build compiler.calls.common.InvokeDynamicPatcher + * @run driver compiler.calls.common.InvokeDynamicPatcher + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::caller -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::callee compiler.calls.common.InvokeDynamic + * -checkCallerCompileLevel 0 -checkCalleeCompileLevel 0 + * @summary check calls from interpreted to interpreted using InvokeDynamic + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2NativeTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2NativeTest.java new file mode 100644 index 00000000000..03fbfdda2a4 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeDynamic2NativeTest.java @@ -0,0 +1,36 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeDynamic + * @build compiler.calls.common.InvokeDynamicPatcher + * @run driver compiler.calls.common.InvokeDynamicPatcher + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeDynamic::caller compiler.calls.common.InvokeDynamic + * -checkCallerCompileLevel 0 -nativeCallee + * @summary check calls from interpreted to native using InvokeDynamic + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2CompiledTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2CompiledTest.java new file mode 100644 index 00000000000..84b4e5016ca --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeInterface + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::caller -Xbatch compiler.calls.common.InvokeInterface + * -checkCallerCompileLevel 0 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::caller -Xbatch compiler.calls.common.InvokeInterface + * -checkCallerCompileLevel 0 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from interpreted to compiled using InvokeInterface + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2InterpretedTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2InterpretedTest.java new file mode 100644 index 00000000000..a4f204f1d34 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeInterface + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::caller -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::callee compiler.calls.common.InvokeInterface + * -checkCallerCompileLevel 0 -checkCalleeCompileLevel 0 + * @summary check calls from interpreted to interpreted using InvokeInterface + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2NativeTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2NativeTest.java new file mode 100644 index 00000000000..ca0044524e0 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeInterface2NativeTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeInterface + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeInterface::caller compiler.calls.common.InvokeInterface + * -checkCallerCompileLevel 0 -nativeCallee + * @summary check calls from interpreted to native using InvokeInterface + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2CompiledTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2CompiledTest.java new file mode 100644 index 00000000000..d47585abf29 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::caller -Xbatch compiler.calls.common.InvokeSpecial + * -checkCallerCompileLevel 0 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::caller -Xbatch compiler.calls.common.InvokeSpecial + * -checkCallerCompileLevel 0 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from interpreted to compiled using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2InterpretedTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2InterpretedTest.java new file mode 100644 index 00000000000..9c047fa9502 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::caller -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::callee compiler.calls.common.InvokeSpecial + * -checkCallerCompileLevel 0 -checkCalleeCompileLevel 0 + * @summary check calls from interpreted to interpreted using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2NativeTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2NativeTest.java new file mode 100644 index 00000000000..768d5eb9dae --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeSpecial2NativeTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::caller compiler.calls.common.InvokeSpecial + * -checkCallerCompileLevel 0 -nativeCallee + * @summary check calls from interpreted to native using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2CompiledTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2CompiledTest.java new file mode 100644 index 00000000000..de4f6c2b995 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::caller -Xbatch compiler.calls.common.InvokeStatic + * -checkCallerCompileLevel 0 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::caller -Xbatch compiler.calls.common.InvokeStatic + * -checkCallerCompileLevel 0 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from interpreted to compiled using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2InterpretedTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2InterpretedTest.java new file mode 100644 index 00000000000..06339099281 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::caller -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::callee compiler.calls.common.InvokeStatic + * -checkCallerCompileLevel 0 -checkCalleeCompileLevel 0 + * @summary check calls from interpreted to interpreted using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2NativeTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2NativeTest.java new file mode 100644 index 00000000000..2a7deda7655 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeStatic2NativeTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::caller compiler.calls.common.InvokeStatic + * -checkCallerCompileLevel 0 -nativeCallee + * @summary check calls from interpreted to native using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2CompiledTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2CompiledTest.java new file mode 100644 index 00000000000..fb7a645ec8d --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::caller -Xbatch compiler.calls.common.InvokeVirtual + * -checkCallerCompileLevel 0 -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::caller -Xbatch compiler.calls.common.InvokeVirtual + * -checkCallerCompileLevel 0 -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from interpreted to compiled using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2InterpretedTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2InterpretedTest.java new file mode 100644 index 00000000000..c4eecef1d80 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::caller -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::callee compiler.calls.common.InvokeVirtual + * -checkCallerCompileLevel 0 -checkCalleeCompileLevel 0 + * @summary check calls from interpreted to interpreted using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2NativeTest.java b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2NativeTest.java new file mode 100644 index 00000000000..2ac9911b4d3 --- /dev/null +++ b/hotspot/test/compiler/calls/fromInterpreted/InterpretedInvokeVirtual2NativeTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::caller compiler.calls.common.InvokeVirtual + * -checkCallerCompileLevel 0 -nativeCallee + * @summary check calls from interpreted to native using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2CompiledTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2CompiledTest.java new file mode 100644 index 00000000000..1a303bdf088 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -nativeCaller -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeSpecial + * -nativeCaller -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from native to compiled using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2InterpretedTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2InterpretedTest.java new file mode 100644 index 00000000000..517422adf6e --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeSpecial::callee compiler.calls.common.InvokeSpecial + * -nativeCaller -checkCalleeCompileLevel 0 + * @summary check calls from native to interpreted using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2NativeTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2NativeTest.java new file mode 100644 index 00000000000..9b3d7ad166a --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeSpecial2NativeTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeSpecial + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.calls.common.InvokeSpecial + * -nativeCaller -nativeCallee + * @summary check calls from native to native using InvokeSpecial + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2CompiledTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2CompiledTest.java new file mode 100644 index 00000000000..546ed827801 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -nativeCaller -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeStatic + * -nativeCaller -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from native to compiled using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2InterpretedTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2InterpretedTest.java new file mode 100644 index 00000000000..5e480d82f36 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeStatic::callee compiler.calls.common.InvokeStatic + * -nativeCaller -checkCalleeCompileLevel 0 + * @summary check calls from native to interpreted using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2NativeTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2NativeTest.java new file mode 100644 index 00000000000..9ace6ea67b5 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeStatic2NativeTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeStatic + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.calls.common.InvokeStatic + * -nativeCaller -nativeCallee + * @summary check calls from native to native using InvokeStatic + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2CompiledTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2CompiledTest.java new file mode 100644 index 00000000000..56059718e81 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2CompiledTest.java @@ -0,0 +1,37 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -nativeCaller -compileCallee 1 -checkCalleeCompileLevel 1 + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -Xbatch compiler.calls.common.InvokeVirtual + * -nativeCaller -compileCallee 4 -checkCalleeCompileLevel 4 + * @summary check calls from native to compiled using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2InterpretedTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2InterpretedTest.java new file mode 100644 index 00000000000..09777265bc3 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2InterpretedTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * -XX:CompileCommand=exclude,compiler.calls.common.InvokeVirtual::callee compiler.calls.common.InvokeVirtual + * -nativeCaller -checkCalleeCompileLevel 0 + * @summary check calls from native to interpreted using InvokeVirtual + */ diff --git a/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2NativeTest.java b/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2NativeTest.java new file mode 100644 index 00000000000..d4ddd119fc3 --- /dev/null +++ b/hotspot/test/compiler/calls/fromNative/NativeInvokeVirtual2NativeTest.java @@ -0,0 +1,34 @@ +/* + * 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 + * @library /test/lib /testlibrary / + * @build compiler.calls.common.InvokeVirtual + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. + * compiler.calls.common.InvokeVirtual + * -nativeCaller -nativeCallee + * @summary check calls from native to native using InvokeVirtual + */ From 8c0ad215bc399e86467b76ef5240aa8f4aded866 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Wed, 16 Dec 2015 15:38:28 +0100 Subject: [PATCH 061/215] 8144246: adding lots of directives via jcmd may produce OOM crash Add a limit to the number of directives Reviewed-by: kvn --- .../src/share/vm/compiler/compileBroker.cpp | 2 +- .../share/vm/compiler/compilerDirectives.cpp | 8 +++++ .../share/vm/compiler/compilerDirectives.hpp | 1 + .../share/vm/compiler/directivesParser.cpp | 32 ++++++++++++++++--- .../share/vm/compiler/directivesParser.hpp | 2 ++ hotspot/src/share/vm/runtime/globals.hpp | 7 ++-- hotspot/src/share/vm/utilities/json.cpp | 1 - .../parser/DirectiveStressTest.java | 2 +- .../parser/HugeDirectiveUtil.java | 1 + 9 files changed, 46 insertions(+), 10 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 9881a31435e..eea5af567bd 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -215,7 +215,7 @@ bool compileBroker_init() { if (DirectivesParser::has_file()) { return DirectivesParser::parse_from_flag(); - } else if (PrintCompilerDirectives) { + } else if (CompilerDirectivesPrint) { // Print default directive even when no other was added DirectivesStack::print(tty); } diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.cpp b/hotspot/src/share/vm/compiler/compilerDirectives.cpp index 4d10aec5307..3d1c9a2fcb1 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.cpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.cpp @@ -487,6 +487,14 @@ void DirectivesStack::pop_inner() { DirectivesStack::release(tmp); } +bool DirectivesStack::check_capacity(int request_size, outputStream* st) { + if ((request_size + _depth) > CompilerDirectivesLimit) { + st->print_cr("Could not add %i more directives. Currently %i/%i directives.", request_size, _depth, CompilerDirectivesLimit); + return false; + } + return true; +} + void DirectivesStack::clear() { // holding the lock during the whole operation ensuring consistent result MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag); diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.hpp b/hotspot/src/share/vm/compiler/compilerDirectives.hpp index 421012c687e..e345a54ee5a 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.hpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.hpp @@ -89,6 +89,7 @@ public: static DirectiveSet* getDefaultDirective(AbstractCompiler* comp); static void push(CompilerDirectives* directive); static void pop(); + static bool check_capacity(int request_size, outputStream* st); static void clear(); static void print(outputStream* st); static void release(DirectiveSet* set); diff --git a/hotspot/src/share/vm/compiler/directivesParser.cpp b/hotspot/src/share/vm/compiler/directivesParser.cpp index 7c2b15404ac..bd69cf1799e 100644 --- a/hotspot/src/share/vm/compiler/directivesParser.cpp +++ b/hotspot/src/share/vm/compiler/directivesParser.cpp @@ -30,6 +30,7 @@ #include void DirectivesParser::push_tmp(CompilerDirectives* dir) { + _tmp_depth++; dir->set_next(_tmp_top); _tmp_top = dir; } @@ -41,17 +42,29 @@ CompilerDirectives* DirectivesParser::pop_tmp() { CompilerDirectives* tmp = _tmp_top; _tmp_top = _tmp_top->next(); tmp->set_next(NULL); + _tmp_depth--; return tmp; } +void DirectivesParser::clean_tmp() { + CompilerDirectives* tmp = pop_tmp(); + while (tmp != NULL) { + delete tmp; + tmp = pop_tmp(); + } + assert(_tmp_depth == 0, "Consistency"); +} + bool DirectivesParser::parse_string(const char* text, outputStream* st) { DirectivesParser cd(text, st); if (cd.valid()) { return cd.install_directives(); + } else { + cd.clean_tmp(); + st->flush(); + st->print_cr("Parsing of compiler directives failed"); + return false; } - st->flush(); - st->print_cr("Parsing of compiler directives failed"); - return false; } bool DirectivesParser::has_file() { @@ -91,6 +104,12 @@ bool DirectivesParser::parse_from_file_inner(const char* filename, outputStream* } bool DirectivesParser::install_directives() { + // Check limit + if (!DirectivesStack::check_capacity(_tmp_depth, _st)) { + clean_tmp(); + return false; + } + // Pop from internal temporary stack and push to compileBroker. CompilerDirectives* tmp = pop_tmp(); int i = 0; @@ -104,7 +123,7 @@ bool DirectivesParser::install_directives() { return false; } else { _st->print_cr("%i compiler directives added", i); - if (PrintCompilerDirectives) { + if (CompilerDirectivesPrint) { // Print entire directives stack after new has been pushed. DirectivesStack::print(_st); } @@ -113,7 +132,7 @@ bool DirectivesParser::install_directives() { } DirectivesParser::DirectivesParser(const char* text, outputStream* st) -: JSON(text, false, st), depth(0), current_directive(NULL), current_directiveset(NULL), _tmp_top(NULL) { +: JSON(text, false, st), depth(0), current_directive(NULL), current_directiveset(NULL), _tmp_top(NULL), _tmp_depth(0) { #ifndef PRODUCT memset(stack, 0, MAX_DEPTH * sizeof(stack[0])); #endif @@ -121,6 +140,8 @@ DirectivesParser::DirectivesParser(const char* text, outputStream* st) } DirectivesParser::~DirectivesParser() { + assert(_tmp_top == NULL, "Consistency"); + assert(_tmp_depth == 0, "Consistency"); } const DirectivesParser::key DirectivesParser::keys[] = { @@ -584,6 +605,7 @@ void DirectivesParser::test(const char* text, bool should_pass) { tty->print("-- DirectivesParser test failed as expected --\n"); } } + cd.clean_tmp(); } bool DirectivesParser::test() { diff --git a/hotspot/src/share/vm/compiler/directivesParser.hpp b/hotspot/src/share/vm/compiler/directivesParser.hpp index 9defc95fab9..d0d7eb31388 100644 --- a/hotspot/src/share/vm/compiler/directivesParser.hpp +++ b/hotspot/src/share/vm/compiler/directivesParser.hpp @@ -126,8 +126,10 @@ private: DirectiveSet* current_directiveset; void push_tmp(CompilerDirectives* dir); + void clean_tmp(); CompilerDirectives* pop_tmp(); CompilerDirectives* _tmp_top; // temporary storage for dirs while parsing + int _tmp_depth; // Number of directives that has been parsed but not installed. static uint mask(keytype kt); diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index acfcd6735f4..eef5fbb3120 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -4268,8 +4268,11 @@ public: diagnostic(bool, CompilerDirectivesIgnoreCompileCommands, false, \ "Disable backwards compatibility for compile commands.") \ \ - diagnostic(bool, PrintCompilerDirectives, false, \ - "Print compiler directives on installation.") + diagnostic(bool, CompilerDirectivesPrint, false, \ + "Print compiler directives on installation.") \ + diagnostic(int, CompilerDirectivesLimit, 50, \ + "Limit on number of compiler directives.") + /* * Macros for factoring of globals diff --git a/hotspot/src/share/vm/utilities/json.cpp b/hotspot/src/share/vm/utilities/json.cpp index e7df3d0de70..2064bb81e7a 100644 --- a/hotspot/src/share/vm/utilities/json.cpp +++ b/hotspot/src/share/vm/utilities/json.cpp @@ -750,7 +750,6 @@ bool JSONTest::test() { JSONTest::test("{ key : 1 }", true); JSONTest::test("{ key : 1, }", true); - JSONTest::test("{ key : 1.2 }", true); JSONTest::test("{ key : true }", true); JSONTest::test("{ key : true, }", true); JSONTest::test("{ key : false }", true); diff --git a/hotspot/test/compiler/compilercontrol/parser/DirectiveStressTest.java b/hotspot/test/compiler/compilercontrol/parser/DirectiveStressTest.java index 8e23273e643..ef1a311beca 100644 --- a/hotspot/test/compiler/compilercontrol/parser/DirectiveStressTest.java +++ b/hotspot/test/compiler/compilercontrol/parser/DirectiveStressTest.java @@ -44,7 +44,7 @@ import java.util.stream.Collectors; public class DirectiveStressTest { private static final int AMOUNT = Integer.getInteger( "compiler.compilercontrol.parser.DirectiveStressTest.amount", - Short.MAX_VALUE * 2 + 2); + 999); private static final List DESCRIPTORS = new PoolHelper().getAllMethods().stream() .map(pair -> AbstractTestBase.getValidMethodDescriptor( diff --git a/hotspot/test/compiler/compilercontrol/parser/HugeDirectiveUtil.java b/hotspot/test/compiler/compilercontrol/parser/HugeDirectiveUtil.java index d5100ccc33d..6bf59324810 100644 --- a/hotspot/test/compiler/compilercontrol/parser/HugeDirectiveUtil.java +++ b/hotspot/test/compiler/compilercontrol/parser/HugeDirectiveUtil.java @@ -117,6 +117,7 @@ public final class HugeDirectiveUtil { try { output = ProcessTools.executeTestJvm( "-XX:+UnlockDiagnosticVMOptions", + "-XX:CompilerDirectivesLimit=1000", "-XX:CompilerDirectivesFile=" + fileName, "-version"); } catch (Throwable thr) { From 2bb757d0eb1999b86bc983d5bcec6c79ed2a0ef3 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Wed, 16 Dec 2015 15:39:11 +0100 Subject: [PATCH 062/215] 8145345: LogCompilation output is empty after JEP165: Compiler Control Fix default init and compilecommand update Reviewed-by: kvn --- .../share/vm/compiler/compilerDirectives.cpp | 21 ++++++++++++------- .../share/vm/compiler/compilerDirectives.hpp | 6 +++--- .../share/vm/compiler/directivesParser.cpp | 2 +- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.cpp b/hotspot/src/share/vm/compiler/compilerDirectives.cpp index 3d1c9a2fcb1..4f6162a96eb 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.cpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.cpp @@ -86,16 +86,21 @@ void CompilerDirectives::print(outputStream* st) { //--- } -void CompilerDirectives::finalize() { +void CompilerDirectives::finalize(outputStream* st) { if (_c1_store != NULL) { - _c1_store->finalize(); + _c1_store->finalize(st); } if (_c2_store != NULL) { - _c2_store->finalize(); + _c2_store->finalize(st); } } -void DirectiveSet::finalize() { +void DirectiveSet::finalize(outputStream* st) { + // Check LogOption and warn + if (LogOption && !LogCompilation) { + st->print_cr("Warning: +LogCompilation must be set to enable compilation logging from directives"); + } + // if any flag has been modified - set directive as enabled // unless it already has been explicitly set. if (!_modified[EnableIndex]) { @@ -252,12 +257,14 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(methodHandle metho changed = true; } } - if (CompilerOracle::should_log(method)) { - if (!_modified[LogIndex]) { - set->LogOption = true; + if (!_modified[LogIndex]) { + bool log = CompilerOracle::should_log(method); + if (log != set->LogOption) { + set->LogOption = log; changed = true; } } + if (CompilerOracle::should_print(method)) { if (!_modified[PrintAssemblyIndex]) { set->PrintAssemblyOption = true; diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.hpp b/hotspot/src/share/vm/compiler/compilerDirectives.hpp index e345a54ee5a..1720aa4c4b3 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.hpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.hpp @@ -39,7 +39,7 @@ cflags(Exclude, bool, false, X) \ cflags(BreakAtExecute, bool, false, X) \ cflags(BreakAtCompile, bool, false, X) \ - cflags(Log, bool, false, X) \ + cflags(Log, bool, LogCompilation, X) \ cflags(PrintAssembly, bool, PrintAssembly, PrintAssembly) \ cflags(PrintInlining, bool, PrintInlining, PrintInlining) \ cflags(PrintNMethods, bool, PrintNMethods, PrintNMethods) \ @@ -117,7 +117,7 @@ public: bool matches_inline(methodHandle method, int inline_action); static DirectiveSet* clone(DirectiveSet const* src); bool is_intrinsic_disabled(methodHandle method); - void finalize(); + void finalize(outputStream* st); typedef enum { #define enum_of_flags(name, type, dvalue, cc_flag) name##Index, @@ -177,7 +177,7 @@ public: DirectiveSet* get_for(AbstractCompiler *comp); void print(outputStream* st); bool is_default_directive() { return _next == NULL; } - void finalize(); + void finalize(outputStream* st); void inc_refcount(); void dec_refcount(); diff --git a/hotspot/src/share/vm/compiler/directivesParser.cpp b/hotspot/src/share/vm/compiler/directivesParser.cpp index bd69cf1799e..16720ceb4db 100644 --- a/hotspot/src/share/vm/compiler/directivesParser.cpp +++ b/hotspot/src/share/vm/compiler/directivesParser.cpp @@ -542,7 +542,7 @@ bool DirectivesParser::callback(JSON_TYPE t, JSON_VAL* v, uint rlimit) { error(INTERNAL_ERROR, "Directive missing required match."); return false; } - current_directive->finalize(); + current_directive->finalize(_st); push_tmp(current_directive); current_directive = NULL; break; From 74cff677d4c9acd1b566442eb09e197a015831f6 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Wed, 9 Dec 2015 13:37:59 +0100 Subject: [PATCH 063/215] 8144091: CompilerControl: directive file doesn't override inlining rules Fix correct overrides Reviewed-by: roland --- .../share/vm/compiler/compilerDirectives.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.cpp b/hotspot/src/share/vm/compiler/compilerDirectives.cpp index 4f6162a96eb..6ffeaa5a6c4 100644 --- a/hotspot/src/share/vm/compiler/compilerDirectives.cpp +++ b/hotspot/src/share/vm/compiler/compilerDirectives.cpp @@ -313,7 +313,7 @@ CompilerDirectives* DirectiveSet::directive() { bool DirectiveSet::matches_inline(methodHandle method, int inline_action) { if (_inlinematchers != NULL) { - if (_inlinematchers->match(method, InlineMatcher::force_inline)) { + if (_inlinematchers->match(method, inline_action)) { return true; } } @@ -325,11 +325,11 @@ bool DirectiveSet::should_inline(ciMethod* inlinee) { VM_ENTRY_MARK; methodHandle mh(THREAD, inlinee->get_Method()); - if (matches_inline(mh, InlineMatcher::force_inline)) { - return true; + if (_inlinematchers != NULL) { + return matches_inline(mh, InlineMatcher::force_inline); } - if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::should_inline(mh)) { - return true; + if (!CompilerDirectivesIgnoreCompileCommandsOption) { + return CompilerOracle::should_inline(mh); } return false; } @@ -339,11 +339,11 @@ bool DirectiveSet::should_not_inline(ciMethod* inlinee) { VM_ENTRY_MARK; methodHandle mh(THREAD, inlinee->get_Method()); - if (matches_inline(mh, InlineMatcher::dont_inline)) { - return true; + if (_inlinematchers != NULL) { + return matches_inline(mh, InlineMatcher::dont_inline); } - if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::should_not_inline(mh)) { - return true; + if (!CompilerDirectivesIgnoreCompileCommandsOption) { + return CompilerOracle::should_not_inline(mh); } return false; } From f23d71b4f4f446dd99d0a7f70928a633c803a87e Mon Sep 17 00:00:00 2001 From: Ambarish Rapte Date: Wed, 9 Dec 2015 18:12:49 +0300 Subject: [PATCH 064/215] 8144915: TextField throws NPE Reviewed-by: ssadetsky, serb --- jdk/src/java.desktop/share/classes/java/awt/TextField.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jdk/src/java.desktop/share/classes/java/awt/TextField.java b/jdk/src/java.desktop/share/classes/java/awt/TextField.java index 2dfd19c4128..7c5563088c3 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/TextField.java +++ b/jdk/src/java.desktop/share/classes/java/awt/TextField.java @@ -309,6 +309,9 @@ public class TextField extends TextComponent { * @return Returns text after replacing EOL characters. */ private static String replaceEOL(String text) { + if (text == null) { + return text; + } String[] strEOLs = {System.lineSeparator(), "\n"}; for (String eol : strEOLs) { if (text.contains(eol)) { From 3144cc4a273306a9f18d6a7863a5386c97b4915d Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Wed, 9 Dec 2015 18:56:59 +0300 Subject: [PATCH 065/215] 8143909: Behavior of null arguments not specified in javax.sound.midi.spi The specification change was reviewed by Florian Bomers also Reviewed-by: amenkov --- .../sound/AbstractMidiDeviceProvider.java | 8 +- .../sun/media/sound/JARSoundbankReader.java | 6 +- .../sound/RealTimeSequencerProvider.java | 5 +- .../com/sun/media/sound/SoftProvider.java | 5 +- .../media/sound/StandardMidiFileWriter.java | 34 ++- .../classes/javax/sound/midi/MidiSystem.java | 82 +++++-- .../sound/midi/spi/MidiDeviceProvider.java | 6 +- .../javax/sound/midi/spi/MidiFileReader.java | 8 +- .../javax/sound/midi/spi/MidiFileWriter.java | 8 +- .../javax/sound/midi/spi/SoundbankReader.java | 5 +- .../midi/MidiDeviceProvider/NullInfo.java | 71 ------ .../MidiDeviceProvider/ExpectedNPEOnNull.java | 94 ++++++++ .../MidiDeviceProvider/FakeInfo.java | 0 .../MidiDeviceProvider/UnsupportedInfo.java | 0 .../spi/MidiFileReader/ExpectedNPEOnNull.java | 130 +++++++++++ .../spi/MidiFileWriter/ExpectedNPEOnNull.java | 215 ++++++++++++++++++ .../SoundbankReader/ExpectedNPEOnNull.java | 94 ++++++++ 17 files changed, 647 insertions(+), 124 deletions(-) delete mode 100644 jdk/test/javax/sound/midi/MidiDeviceProvider/NullInfo.java create mode 100644 jdk/test/javax/sound/midi/spi/MidiDeviceProvider/ExpectedNPEOnNull.java rename jdk/test/javax/sound/midi/{ => spi}/MidiDeviceProvider/FakeInfo.java (100%) rename jdk/test/javax/sound/midi/{ => spi}/MidiDeviceProvider/UnsupportedInfo.java (100%) create mode 100644 jdk/test/javax/sound/midi/spi/MidiFileReader/ExpectedNPEOnNull.java create mode 100644 jdk/test/javax/sound/midi/spi/MidiFileWriter/ExpectedNPEOnNull.java create mode 100644 jdk/test/javax/sound/midi/spi/SoundbankReader/ExpectedNPEOnNull.java diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDeviceProvider.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDeviceProvider.java index 8d0003cc987..6ff1ccde6b0 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDeviceProvider.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AbstractMidiDeviceProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -25,10 +25,11 @@ package com.sun.media.sound; +import java.util.Objects; + import javax.sound.midi.MidiDevice; import javax.sound.midi.spi.MidiDeviceProvider; - /** * Super class for MIDI input or output device provider. * @@ -127,7 +128,8 @@ public abstract class AbstractMidiDeviceProvider extends MidiDeviceProvider { } @Override - public final MidiDevice getDevice(MidiDevice.Info info) { + public final MidiDevice getDevice(final MidiDevice.Info info) { + Objects.requireNonNull(info); if (info instanceof Info) { readDeviceInfos(); MidiDevice[] devices = getDeviceCache(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java index 32fc90ffbb7..30c49810771 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -22,6 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package com.sun.media.sound; import java.io.BufferedReader; @@ -32,6 +33,8 @@ import java.io.InputStreamReader; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; +import java.util.Objects; + import javax.sound.midi.InvalidMidiDataException; import javax.sound.midi.Soundbank; import javax.sound.midi.spi.SoundbankReader; @@ -112,6 +115,7 @@ public final class JARSoundbankReader extends SoundbankReader { public Soundbank getSoundbank(InputStream stream) throws InvalidMidiDataException, IOException { + Objects.requireNonNull(stream); return null; } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencerProvider.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencerProvider.java index fa5bfa1afbf..32ca9ff5331 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencerProvider.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/RealTimeSequencerProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -25,6 +25,8 @@ package com.sun.media.sound; +import java.util.Objects; + import javax.sound.midi.MidiDevice; import javax.sound.midi.spi.MidiDeviceProvider; @@ -42,6 +44,7 @@ public final class RealTimeSequencerProvider extends MidiDeviceProvider { @Override public MidiDevice getDevice(final MidiDevice.Info info) { + Objects.requireNonNull(info); if (RealTimeSequencer.info.equals(info)) { return new RealTimeSequencer(); } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftProvider.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftProvider.java index 89d85362539..e4bc1a7e342 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftProvider.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -25,6 +25,8 @@ package com.sun.media.sound; +import java.util.Objects; + import javax.sound.midi.MidiDevice; import javax.sound.midi.spi.MidiDeviceProvider; @@ -42,6 +44,7 @@ public final class SoftProvider extends MidiDeviceProvider { @Override public MidiDevice getDevice(final MidiDevice.Info info) { + Objects.requireNonNull(info); if (SoftSynthesizer.info.equals(info)) { return new SoftSynthesizer(); } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java index f03921e72df..cc75e40e251 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -25,21 +25,22 @@ package com.sun.media.sound; -import java.io.DataOutputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; -import java.io.SequenceInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.io.SequenceInputStream; +import java.util.Objects; import javax.sound.midi.InvalidMidiDataException; -import javax.sound.midi.MidiEvent; import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiEvent; import javax.sound.midi.Sequence; import javax.sound.midi.ShortMessage; import javax.sound.midi.SysexMessage; @@ -115,24 +116,16 @@ public final class StandardMidiFileWriter extends MidiFileWriter { return typesArray; } - public boolean isFileTypeSupported(int type) { - for(int i=0; i providers = getMidiFileReaders(); MidiFileFormat format = null; @@ -602,11 +613,13 @@ public class MidiSystem { * @throws InvalidMidiDataException if the URL does not point to valid MIDI * file data recognized by the system * @throws IOException if an I/O exception occurs while accessing the URL + * @throws NullPointerException if {@code url} is {@code null} * @see #getMidiFileFormat(InputStream) * @see #getMidiFileFormat(File) */ - public static MidiFileFormat getMidiFileFormat(URL url) - throws InvalidMidiDataException, IOException { + public static MidiFileFormat getMidiFileFormat(final URL url) + throws InvalidMidiDataException, IOException { + Objects.requireNonNull(url); List providers = getMidiFileReaders(); MidiFileFormat format = null; @@ -646,11 +659,13 @@ public class MidiSystem { * @throws InvalidMidiDataException if the {@code File} does not point to * valid MIDI file data recognized by the system * @throws IOException if an I/O exception occurs while accessing the file + * @throws NullPointerException if {@code file} is {@code null} * @see #getMidiFileFormat(InputStream) * @see #getMidiFileFormat(URL) */ - public static MidiFileFormat getMidiFileFormat(File file) - throws InvalidMidiDataException, IOException { + public static MidiFileFormat getMidiFileFormat(final File file) + throws InvalidMidiDataException, IOException { + Objects.requireNonNull(file); List providers = getMidiFileReaders(); MidiFileFormat format = null; @@ -699,11 +714,13 @@ public class MidiSystem { * @throws InvalidMidiDataException if the stream does not point to valid * MIDI file data recognized by the system * @throws IOException if an I/O exception occurs while accessing the stream + * @throws NullPointerException if {@code stream} is {@code null} * @see InputStream#markSupported * @see InputStream#mark */ - public static Sequence getSequence(InputStream stream) - throws InvalidMidiDataException, IOException { + public static Sequence getSequence(final InputStream stream) + throws InvalidMidiDataException, IOException { + Objects.requireNonNull(stream); List providers = getMidiFileReaders(); Sequence sequence = null; @@ -743,9 +760,11 @@ public class MidiSystem { * @throws InvalidMidiDataException if the URL does not point to valid MIDI * file data recognized by the system * @throws IOException if an I/O exception occurs while accessing the URL + * @throws NullPointerException if {@code url} is {@code null} */ - public static Sequence getSequence(URL url) - throws InvalidMidiDataException, IOException { + public static Sequence getSequence(final URL url) + throws InvalidMidiDataException, IOException { + Objects.requireNonNull(url); List providers = getMidiFileReaders(); Sequence sequence = null; @@ -787,9 +806,11 @@ public class MidiSystem { * @throws InvalidMidiDataException if the File does not point to valid MIDI * file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code file} is {@code null} */ - public static Sequence getSequence(File file) - throws InvalidMidiDataException, IOException { + public static Sequence getSequence(final File file) + throws InvalidMidiDataException, IOException { + Objects.requireNonNull(file); List providers = getMidiFileReaders(); Sequence sequence = null; @@ -870,8 +891,10 @@ public class MidiSystem { * @param sequence the sequence for which MIDI file type support is queried * @return the set of unique supported file types. If no file types are * supported, returns an array of length 0. + * @throws NullPointerException if {@code sequence} is {@code null} */ - public static int[] getMidiFileTypes(Sequence sequence) { + public static int[] getMidiFileTypes(final Sequence sequence) { + Objects.requireNonNull(sequence); List providers = getMidiFileWriters(); Set allTypes = new HashSet<>(); @@ -903,8 +926,11 @@ public class MidiSystem { * @param sequence the sequence for which file writing support is queried * @return {@code true} if the file type is supported for this sequence, * otherwise {@code false} + * @throws NullPointerException if {@code sequence} is {@code null} */ - public static boolean isFileTypeSupported(int fileType, Sequence sequence) { + public static boolean isFileTypeSupported(final int fileType, + final Sequence sequence) { + Objects.requireNonNull(sequence); List providers = getMidiFileWriters(); @@ -929,10 +955,15 @@ public class MidiSystem { * @throws IOException if an I/O exception occurs * @throws IllegalArgumentException if the file format is not supported by * the system + * @throws NullPointerException if {@code in} or {@code out} are + * {@code null} * @see #isFileTypeSupported(int, Sequence) * @see #getMidiFileTypes(Sequence) */ - public static int write(Sequence in, int fileType, OutputStream out) throws IOException { + public static int write(final Sequence in, final int fileType, + final OutputStream out) throws IOException { + Objects.requireNonNull(in); + Objects.requireNonNull(out); List providers = getMidiFileWriters(); //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences @@ -963,10 +994,15 @@ public class MidiSystem { * @throws IOException if an I/O exception occurs * @throws IllegalArgumentException if the file type is not supported by the * system + * @throws NullPointerException if {@code in} or {@code out} are + * {@code null} * @see #isFileTypeSupported(int, Sequence) * @see #getMidiFileTypes(Sequence) */ - public static int write(Sequence in, int type, File out) throws IOException { + public static int write(final Sequence in, final int type, final File out) + throws IOException { + Objects.requireNonNull(in); + Objects.requireNonNull(out); List providers = getMidiFileWriters(); //$$fb 2002-04-17: Fix for 4635287: Standard MidiFileWriter cannot write empty Sequences diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiDeviceProvider.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiDeviceProvider.java index 97c9d92b7f0..4f820b497d7 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiDeviceProvider.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiDeviceProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -26,6 +26,7 @@ package javax.sound.midi.spi; import java.util.Arrays; +import java.util.Objects; import javax.sound.midi.MidiDevice; @@ -46,8 +47,10 @@ public abstract class MidiDeviceProvider { * is queried * @return {@code true} if the specified device is supported, otherwise * {@code false} + * @throws NullPointerException if {@code info} is {@code null} */ public boolean isDeviceSupported(final MidiDevice.Info info) { + Objects.requireNonNull(info); return Arrays.asList(getDeviceInfo()).contains(info); } @@ -67,6 +70,7 @@ public abstract class MidiDeviceProvider { * @throws IllegalArgumentException if the info object specified does not * match the info object for a device supported by this * {@code MidiDeviceProvider} + * @throws NullPointerException if {@code info} is {@code null} */ public abstract MidiDevice getDevice(MidiDevice.Info info); } diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java index bbdca9e97bb..f1c3b6f6ff5 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -60,6 +60,7 @@ public abstract class MidiFileReader { * @throws InvalidMidiDataException if the stream does not point to valid * MIDI file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code stream} is {@code null} * @see InputStream#markSupported * @see InputStream#mark */ @@ -76,6 +77,7 @@ public abstract class MidiFileReader { * @throws InvalidMidiDataException if the URL does not point to valid MIDI * file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code url} is {@code null} */ public abstract MidiFileFormat getMidiFileFormat(URL url) throws InvalidMidiDataException, IOException; @@ -90,6 +92,7 @@ public abstract class MidiFileReader { * @throws InvalidMidiDataException if the {@code File} does not point to * valid MIDI file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code file} is {@code null} */ public abstract MidiFileFormat getMidiFileFormat(File file) throws InvalidMidiDataException, IOException; @@ -110,6 +113,7 @@ public abstract class MidiFileReader { * @throws InvalidMidiDataException if the stream does not point to valid * MIDI file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code stream} is {@code null} * @see InputStream#markSupported * @see InputStream#mark */ @@ -126,6 +130,7 @@ public abstract class MidiFileReader { * @throws InvalidMidiDataException if the URL does not point to valid MIDI * file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code url} is {@code null} */ public abstract Sequence getSequence(URL url) throws InvalidMidiDataException, IOException; @@ -141,6 +146,7 @@ public abstract class MidiFileReader { * @throws InvalidMidiDataException if the {@code File} does not point to * valid MIDI file data recognized by the system * @throws IOException if an I/O exception occurs + * @throws NullPointerException if {@code file} is {@code null} */ public abstract Sequence getSequence(File file) throws InvalidMidiDataException, IOException; diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileWriter.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileWriter.java index a1800f7f701..9a3fdcbc62e 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileWriter.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/MidiFileWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -58,6 +58,7 @@ public abstract class MidiFileWriter { * queried * @return array of file types. If no file types are supported, returns an * array of length 0. + * @throws NullPointerException if {@code sequence} is {@code null} */ public abstract int[] getMidiFileTypes(Sequence sequence); @@ -88,6 +89,7 @@ public abstract class MidiFileWriter { * @param sequence the sequence for which file writing support is queried * @return {@code true} if the file type is supported for this sequence, * otherwise {@code false} + * @throws NullPointerException if {@code sequence} is {@code null} */ public boolean isFileTypeSupported(int fileType, Sequence sequence) { @@ -111,6 +113,8 @@ public abstract class MidiFileWriter { * @throws IOException if an I/O exception occurs * @throws IllegalArgumentException if the file type is not supported by * this file writer + * @throws NullPointerException if {@code in} or {@code out} are + * {@code null} * @see #isFileTypeSupported(int, Sequence) * @see #getMidiFileTypes(Sequence) */ @@ -129,6 +133,8 @@ public abstract class MidiFileWriter { * @throws IOException if an I/O exception occurs * @throws IllegalArgumentException if the file type is not supported by * this file writer + * @throws NullPointerException if {@code in} or {@code out} are + * {@code null} * @see #isFileTypeSupported(int, Sequence) * @see #getMidiFileTypes(Sequence) */ diff --git a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java index 501c18b6ad5..8690b0d18ed 100644 --- a/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java +++ b/jdk/src/java.desktop/share/classes/javax/sound/midi/spi/SoundbankReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -52,6 +52,7 @@ public abstract class SoundbankReader { * @throws InvalidMidiDataException if the URL does not point to valid MIDI * soundbank data recognized by this soundbank reader * @throws IOException if an I/O error occurs + * @throws NullPointerException if {@code url} is {@code null} */ public abstract Soundbank getSoundbank(URL url) throws InvalidMidiDataException, IOException; @@ -64,6 +65,7 @@ public abstract class SoundbankReader { * @throws InvalidMidiDataException if the stream does not point to valid * MIDI soundbank data recognized by this soundbank reader * @throws IOException if an I/O error occurs + * @throws NullPointerException if {@code stream} is {@code null} */ public abstract Soundbank getSoundbank(InputStream stream) throws InvalidMidiDataException, IOException; @@ -76,6 +78,7 @@ public abstract class SoundbankReader { * @throws InvalidMidiDataException if the file does not point to valid MIDI * soundbank data recognized by this soundbank reader * @throws IOException if an I/O error occurs + * @throws NullPointerException if {@code file} is {@code null} */ public abstract Soundbank getSoundbank(File file) throws InvalidMidiDataException, IOException; diff --git a/jdk/test/javax/sound/midi/MidiDeviceProvider/NullInfo.java b/jdk/test/javax/sound/midi/MidiDeviceProvider/NullInfo.java deleted file mode 100644 index 9fa00c03172..00000000000 --- a/jdk/test/javax/sound/midi/MidiDeviceProvider/NullInfo.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.util.Collection; -import java.util.HashSet; - -import javax.sound.midi.MidiDevice; -import javax.sound.midi.MidiSystem; -import javax.sound.midi.MidiUnavailableException; -import javax.sound.midi.spi.MidiDeviceProvider; - -import static java.util.ServiceLoader.load; - -/** - * @test - * @bug 8058115 - * @summary MidiDeviceProvider shouldn't returns incorrect results or throw NPE - * in case of null MidiDevice.Info - * @author Sergey Bylokhov - */ -public final class NullInfo { - - public static void main(final String[] args) { - // MidiSystem API - try { - MidiSystem.getMidiDevice(null); - throw new RuntimeException("IllegalArgumentException expected"); - } catch (final MidiUnavailableException e) { - throw new RuntimeException("IllegalArgumentException expected", e); - } catch (final IllegalArgumentException ignored) { - // expected - } - // MidiDeviceProvider API - final Collection errors = new HashSet<>(); - for (final MidiDeviceProvider mdp : load(MidiDeviceProvider.class)) { - try { - if (mdp.isDeviceSupported(null)) { - throw new RuntimeException("null is supported"); - } - final MidiDevice device = mdp.getDevice(null); - System.err.println("MidiDevice: " + device); - throw new RuntimeException("IllegalArgumentException expected"); - } catch (final IllegalArgumentException e) { - errors.add(e.getMessage()); - } - } - if (errors.size() != 1) { - throw new RuntimeException("Wrong number of messages:" + errors); - } - } -} diff --git a/jdk/test/javax/sound/midi/spi/MidiDeviceProvider/ExpectedNPEOnNull.java b/jdk/test/javax/sound/midi/spi/MidiDeviceProvider/ExpectedNPEOnNull.java new file mode 100644 index 00000000000..efb57eeeae2 --- /dev/null +++ b/jdk/test/javax/sound/midi/spi/MidiDeviceProvider/ExpectedNPEOnNull.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +import java.util.Objects; + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.spi.MidiDeviceProvider; + +import static java.util.ServiceLoader.load; + +/** + * @test + * @bug 8143909 + * @author Sergey Bylokhov + */ +public final class ExpectedNPEOnNull { + + public static void main(final String[] args) throws Exception { + testMS(); + for (final MidiDeviceProvider mdp : load(MidiDeviceProvider.class)) { + testMDP(mdp); + } + testMDP(customMDP); + } + + /** + * Tests the part of MidiSystem API, which implemented via + * MidiDeviceProvider. + */ + private static void testMS() throws Exception { + // MidiSystem#getMidiDevice(MidiDevice.Info) + try { + MidiSystem.getMidiDevice(null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + /** + * Tests the MidiDeviceProvider API directly. + */ + private static void testMDP(final MidiDeviceProvider mdp) throws Exception { + // MidiDeviceProvider#isDeviceSupported(Info) + try { + mdp.isDeviceSupported(null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiDeviceProvider#getDevice(Info) + try { + mdp.getDevice(null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + /** + * Tests some default implementation of MidiDeviceProvider API, using the + * custom {@code MidiDeviceProvider}, which support nothing. + */ + static MidiDeviceProvider customMDP = new MidiDeviceProvider() { + @Override + public MidiDevice.Info[] getDeviceInfo() { + return new MidiDevice.Info[0]; + } + + @Override + public MidiDevice getDevice(MidiDevice.Info info) { + Objects.requireNonNull(info); + return null; + } + }; +} diff --git a/jdk/test/javax/sound/midi/MidiDeviceProvider/FakeInfo.java b/jdk/test/javax/sound/midi/spi/MidiDeviceProvider/FakeInfo.java similarity index 100% rename from jdk/test/javax/sound/midi/MidiDeviceProvider/FakeInfo.java rename to jdk/test/javax/sound/midi/spi/MidiDeviceProvider/FakeInfo.java diff --git a/jdk/test/javax/sound/midi/MidiDeviceProvider/UnsupportedInfo.java b/jdk/test/javax/sound/midi/spi/MidiDeviceProvider/UnsupportedInfo.java similarity index 100% rename from jdk/test/javax/sound/midi/MidiDeviceProvider/UnsupportedInfo.java rename to jdk/test/javax/sound/midi/spi/MidiDeviceProvider/UnsupportedInfo.java diff --git a/jdk/test/javax/sound/midi/spi/MidiFileReader/ExpectedNPEOnNull.java b/jdk/test/javax/sound/midi/spi/MidiFileReader/ExpectedNPEOnNull.java new file mode 100644 index 00000000000..bb4b75f3302 --- /dev/null +++ b/jdk/test/javax/sound/midi/spi/MidiFileReader/ExpectedNPEOnNull.java @@ -0,0 +1,130 @@ +/* + * 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. + */ + +import java.io.File; +import java.io.InputStream; +import java.net.URL; + +import javax.sound.midi.MidiSystem; +import javax.sound.midi.spi.MidiFileReader; + +import static java.util.ServiceLoader.load; + +/** + * @test + * @bug 8143909 + * @author Sergey Bylokhov + */ +public final class ExpectedNPEOnNull { + + public static void main(final String[] args) throws Exception { + testMS(); + for (final MidiFileReader mfr : load(MidiFileReader.class)) { + testMFR(mfr); + } + } + + /** + * Tests the part of MidiSystem API, which implemented via MidiFileReader. + */ + private static void testMS() throws Exception { + // MidiSystem#getMidiFileFormat(InputStream) + try { + MidiSystem.getMidiFileFormat((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getMidiFileFormat(URL) + try { + MidiSystem.getMidiFileFormat((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getMidiFileFormat(File) + try { + MidiSystem.getMidiFileFormat((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getSequence(InputStream) + try { + MidiSystem.getSequence((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getSequence(URL) + try { + MidiSystem.getSequence((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getSequence(File) + try { + MidiSystem.getSequence((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + /** + * Tests the MidiFileReader API directly. + */ + private static void testMFR(final MidiFileReader mfr) throws Exception { + // MidiFileReader#getMidiFileFormat(InputStream) + try { + mfr.getMidiFileFormat((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiFileReader#getMidiFileFormat(URL) + try { + mfr.getMidiFileFormat((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiFileReader#getMidiFileFormat(File) + try { + mfr.getMidiFileFormat((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiFileReader#getSequence(InputStream) + try { + mfr.getSequence((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiFileReader#getSequence(URL) + try { + mfr.getSequence((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiFileReader#getSequence(File) + try { + mfr.getSequence((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } +} diff --git a/jdk/test/javax/sound/midi/spi/MidiFileWriter/ExpectedNPEOnNull.java b/jdk/test/javax/sound/midi/spi/MidiFileWriter/ExpectedNPEOnNull.java new file mode 100644 index 00000000000..6a96dbe6b52 --- /dev/null +++ b/jdk/test/javax/sound/midi/spi/MidiFileWriter/ExpectedNPEOnNull.java @@ -0,0 +1,215 @@ +/* + * 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. + */ + +import java.io.File; +import java.io.OutputStream; +import java.util.Objects; + +import javax.sound.midi.MidiSystem; +import javax.sound.midi.Sequence; +import javax.sound.midi.spi.MidiFileWriter; + +import static java.util.ServiceLoader.load; + +/** + * @test + * @bug 8143909 + * @author Sergey Bylokhov + */ +public final class ExpectedNPEOnNull { + + public static void main(final String[] args) throws Exception { + testMS(); + for (final MidiFileWriter mfw : load(MidiFileWriter.class)) { + testMFW(mfw); + } + testMFW(customMFW); + } + + /** + * Tests the part of MidiSystem API, which implemented via MidiFileWriter. + */ + private static void testMS() throws Exception { + // MidiSystem#getMidiFileTypes(Sequence) + try { + MidiSystem.getMidiFileTypes(null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + + // MidiSystem#isFileTypeSupported(int, Sequence) + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.isFileTypeSupported(type, null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + // MidiSystem#write(Sequence, int, OutputStream) + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.write(null, type, new NullOutputStream()); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.write(new Sequence(0, 0), type, (OutputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.write(null, type, (OutputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + // MidiSystem#write(Sequence, int, File) + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.write(null, type, new File("")); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.write(new Sequence(0, 0), type, (File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + MidiSystem.write(null, type, (File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + } + + /** + * Tests the MidiFileWriter API directly. + */ + private static void testMFW(final MidiFileWriter mfw) throws Exception { + // MidiFileWriter#getMidiFileTypes(Sequence) + try { + mfw.getMidiFileTypes(null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiFileWriter#isFileTypeSupported(int, Sequence) + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.isFileTypeSupported(type, null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + // MidiFileWriter#write(Sequence, int, OutputStream) + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.write(null, type, new NullOutputStream()); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.write(new Sequence(0, 0), type, (OutputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.write(null, type, (OutputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + // MidiFileWriter#write(Sequence, int, File) + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.write(null, type, new File("")); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.write(new Sequence(0, 0), type, (File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + for (final int type : MidiSystem.getMidiFileTypes()) { + try { + mfw.write(null, type, (File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + } + /** + * Tests some default implementation of MidiFileWriter API, using the custom + * {@code MidiFileWriter}, which support nothing. + */ + static MidiFileWriter customMFW = new MidiFileWriter() { + @Override + public int[] getMidiFileTypes() { + return new int[0]; + } + + @Override + public int[] getMidiFileTypes(Sequence sequence) { + Objects.requireNonNull(sequence); + return new int[0]; + } + + @Override + public int write(Sequence in, int fileType, OutputStream out) { + Objects.requireNonNull(in); + Objects.requireNonNull(out); + return 0; + } + + @Override + public int write(Sequence in, int fileType, File out) { + Objects.requireNonNull(in); + Objects.requireNonNull(out); + return 0; + } + }; + + private static final class NullOutputStream extends OutputStream { + + @Override + public void write(final int b) { + //do nothing + } + } +} diff --git a/jdk/test/javax/sound/midi/spi/SoundbankReader/ExpectedNPEOnNull.java b/jdk/test/javax/sound/midi/spi/SoundbankReader/ExpectedNPEOnNull.java new file mode 100644 index 00000000000..6ce3742fc9e --- /dev/null +++ b/jdk/test/javax/sound/midi/spi/SoundbankReader/ExpectedNPEOnNull.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +import java.io.File; +import java.io.InputStream; +import java.net.URL; + +import javax.sound.midi.MidiSystem; +import javax.sound.midi.spi.SoundbankReader; + +import static java.util.ServiceLoader.load; + +/** + * @test + * @bug 8143909 + * @author Sergey Bylokhov + */ +public final class ExpectedNPEOnNull { + + public static void main(final String[] args) throws Exception { + testMS(); + for (final SoundbankReader sbr : load(SoundbankReader.class)) { + testSBR(sbr); + } + } + + /** + * Tests the part of MidiSystem API, which implemented via SoundbankReader. + */ + private static void testMS() throws Exception { + // MidiSystem#getSoundbank(InputStream) + try { + MidiSystem.getSoundbank((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getSoundbank(URL) + try { + MidiSystem.getSoundbank((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // MidiSystem#getSoundbank(File) + try { + MidiSystem.getSoundbank((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } + + /** + * Tests the SoundbankReader API directly. + */ + private static void testSBR(final SoundbankReader sbr) throws Exception { + // SoundbankReader#getSoundbank(InputStream) + try { + sbr.getSoundbank((InputStream) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // SoundbankReader#getSoundbank(URL) + try { + sbr.getSoundbank((URL) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + // SoundbankReader#getSoundbank(File) + try { + sbr.getSoundbank((File) null); + throw new RuntimeException("NPE is expected"); + } catch (final NullPointerException ignored) { + } + } +} From dcf0684317b79872294bc77c3a668ba237e30d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Bourg=C3=A8s?= Date: Wed, 9 Dec 2015 13:59:45 -0800 Subject: [PATCH 066/215] 8144828: Marlin renderer causes unaligned write accesses Reviewed-by: prr, flar --- .../sun/java2d/marlin/MarlinCache.java | 25 ++++++++++++++----- .../sun/java2d/marlin/MarlinConst.java | 2 ++ 2 files changed, 21 insertions(+), 6 deletions(-) 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 a281b4e5ecf..9aa35132772 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 @@ -156,8 +156,6 @@ public final class MarlinCache implements MarlinConst { // rewritten to avoid division: || (width * heightSubPixel) > ((edgeSumDeltaY - heightSubPixel) << BLOCK_SIZE_LG); -// ((edgeSumDeltaY - heightSubPixel) * RLE_THRESHOLD); -// ((edgeSumDeltaY - heightSubPixel) << BLOCK_TH_LG); if (doTrace && !useRLE) { final float meanCrossings @@ -293,8 +291,10 @@ public final class MarlinCache implements MarlinConst { // update row index to current position: rowAAChunkIndex[row] = pos; - // determine need array size (may overflow): - final long needSize = pos + (px_bbox1 - px0); + // determine need array size: + // for RLE encoding, position must be aligned to 4 bytes (int): + // align - 1 = 3 so add +3 and round-off by mask ~3 = -4 + final long needSize = pos + ((px_bbox1 - px0 + 3) & -4); // update next position (bytes): rowAAChunkPos = needSize; @@ -401,8 +401,7 @@ public final class MarlinCache implements MarlinConst { // determine need array size: // pessimistic: max needed size = deltaX x 4 (1 int) - final int maxLen = (to - from); - final long needSize = initialPos + (maxLen << 2); + final long needSize = initialPos + ((to - from) << 2); // update row data: OffHeapArray _rowAAChunk = rowAAChunk; @@ -465,6 +464,13 @@ public final class MarlinCache implements MarlinConst { // note: last pixel exclusive (>= 0) // note: it should check X is smaller than 23bits (overflow)! + // check address alignment to 4 bytes: + if (doCheckUnsafe) { + if ((addr_off & 3) != 0) { + MarlinUtils.logInfo("Misaligned Unsafe address: " + addr_off); + } + } + // special case to encode entries into a single int: if (val == 0) { _unsafe.putInt(addr_off, @@ -521,6 +527,13 @@ public final class MarlinCache implements MarlinConst { // note: last pixel exclusive (>= 0) // note: it should check X is smaller than 23bits (overflow)! + // check address alignment to 4 bytes: + if (doCheckUnsafe) { + if ((addr_off & 3) != 0) { + MarlinUtils.logInfo("Misaligned Unsafe address: " + addr_off); + } + } + // special case to encode entries into a single int: if (val == 0) { _unsafe.putInt(addr_off, diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java index 6ff24a04b64..e799504318d 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java @@ -40,6 +40,8 @@ interface MarlinConst { // log misc.Unsafe alloc/realloc/free static final boolean logUnsafeMalloc = enableLogs && MarlinProperties.isLogUnsafeMalloc(); + // do check unsafe alignment: + static final boolean doCheckUnsafe = false; // do statistics static final boolean doStats = enableLogs && MarlinProperties.isDoStats(); From 5999226f522df00e970dbc84a94f11df0350f605 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 9 Dec 2015 15:20:39 -0800 Subject: [PATCH 067/215] 8137106: EUDC (End User Defined Characters) are not displayed on Windows with Java 8u60+ Reviewed-by: serb, jgodinez --- .../share/classes/sun/font/TrueTypeFont.java | 33 ++++++++++++++----- .../classes/sun/awt/Win32FontManager.java | 2 +- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java b/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java index c4893b6dd60..7668b6572a8 100644 --- a/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java +++ b/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java @@ -176,6 +176,13 @@ public class TrueTypeFont extends FileFont { private String localeFamilyName; private String localeFullName; + public TrueTypeFont(String platname, Object nativeNames, int fIndex, + boolean javaRasterizer) + throws FontFormatException + { + this(platname, nativeNames, fIndex, javaRasterizer, true); + } + /** * - does basic verification of the file * - reads the header table for this font (within a collection) @@ -186,14 +193,17 @@ public class TrueTypeFont extends FileFont { * or fails verification, or there's no usable cmap */ public TrueTypeFont(String platname, Object nativeNames, int fIndex, - boolean javaRasterizer) + boolean javaRasterizer, boolean useFilePool) throws FontFormatException { super(platname, nativeNames); useJavaRasterizer = javaRasterizer; fontRank = Font2D.TTF_RANK; try { - verify(); + verify(useFilePool); init(fIndex); + if (!useFilePool) { + close(); + } } catch (Throwable t) { close(); if (t instanceof FontFormatException) { @@ -280,6 +290,10 @@ public class TrueTypeFont extends FileFont { } + private synchronized FileChannel open() throws FontFormatException { + return open(true); + } + /* This is intended to be called, and the returned value used, * from within a block synchronized on this font object. * ie the channel returned may be nulled out at any time by "close()" @@ -287,7 +301,8 @@ public class TrueTypeFont extends FileFont { * Deadlock warning: FontManager.addToPool(..) acquires a global lock, * which means nested locks may be in effect. */ - private synchronized FileChannel open() throws FontFormatException { + private synchronized FileChannel open(boolean usePool) + throws FontFormatException { if (disposerRecord.channel == null) { if (FontUtilities.isLogging()) { FontUtilities.getLogger().info("open TTF: " + platName); @@ -306,9 +321,11 @@ public class TrueTypeFont extends FileFont { }); disposerRecord.channel = raf.getChannel(); fileSize = (int)disposerRecord.channel.size(); - FontManager fm = FontManagerFactory.getInstance(); - if (fm instanceof SunFontManager) { - ((SunFontManager) fm).addToPool(this); + if (usePool) { + FontManager fm = FontManagerFactory.getInstance(); + if (fm instanceof SunFontManager) { + ((SunFontManager) fm).addToPool(this); + } } } catch (NullPointerException e) { close(); @@ -492,8 +509,8 @@ public class TrueTypeFont extends FileFont { } } - private void verify() throws FontFormatException { - open(); + private void verify(boolean usePool) throws FontFormatException { + open(usePool); } /* sizes, in bytes, of TT/TTC header records */ diff --git a/jdk/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java b/jdk/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java index ee50f24a293..815393eaa1c 100644 --- a/jdk/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java +++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java @@ -61,7 +61,7 @@ public final class Win32FontManager extends SunFontManager { * enumerate (allow direct use) of EUDC fonts. */ eudcFont = new TrueTypeFont(eudcFile, null, 0, - true); + true, false); } catch (FontFormatException e) { } } From 7d9d3a469949a3874f35ebacb140e0aaf49c12f0 Mon Sep 17 00:00:00 2001 From: Avik Niyogi Date: Thu, 10 Dec 2015 14:21:44 +0300 Subject: [PATCH 068/215] 8139169: [macosx] Action registered for keyboard shortcut is called twice Reviewed-by: serb, alexsch --- .../native/libawt_lwawt/awt/CMenuItem.m | 300 ++++++++++-------- .../8139169/ScreenMenuBarInputTwice.java | 234 ++++++++++++++ 2 files changed, 405 insertions(+), 129 deletions(-) create mode 100644 jdk/test/javax/swing/JMenuItem/8139169/ScreenMenuBarInputTwice.java diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m index 8e483468074..28e4f386d78 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m @@ -24,6 +24,7 @@ */ #import +#include #import "CMenuItem.h" #import "CMenu.h" @@ -40,7 +41,7 @@ @implementation CMenuItem - (id) initWithPeer:(jobject)peer asSeparator: (NSNumber *) asSeparator{ -AWT_ASSERT_APPKIT_THREAD; + AWT_ASSERT_APPKIT_THREAD; self = [super initWithPeer:peer]; if (self) { if ([asSeparator boolValue]) { @@ -63,13 +64,48 @@ AWT_ASSERT_APPKIT_THREAD; - (BOOL) worksWhenModal { return YES; } +// This is a method written using Carbon framework methods to remove +// All modifiers including "Shift" modifier. +// Example 1: Shortcut set is "Command Shift m" returns "m" +// Example 2: Shortcut set is "Command m" returns "m" +// Example 3: Shortcut set is "Alt Shift ," returns "," + +CFStringRef createStringForKey(CGKeyCode keyCode) +{ + TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); +// currentKeyboard now contains the current input source + CFDataRef layoutData = + TISGetInputSourceProperty(currentKeyboard, + kTISPropertyUnicodeKeyLayoutData); +// the UNICODE keyLayout is fetched from currentKeyboard in layoutData + const UCKeyboardLayout *keyboardLayout = + (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); +// A read-only data pointer is fetched from layoutData + UInt32 keysDown = 0; + UniChar chars[4]; + UniCharCount realLength; + + UCKeyTranslate(keyboardLayout, + keyCode, + kUCKeyActionDisplay, + 0, + LMGetKbdType(), + kUCKeyTranslateNoDeadKeysBit, + &keysDown, + sizeof(chars) / sizeof(chars[0]), + &realLength, + chars); + CFRelease(currentKeyboard); +// Converts keyCode, modifier and dead-key state into UNICODE characters + return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1); +} // Events - (void)handleAction:(NSMenuItem *)sender { -AWT_ASSERT_APPKIT_THREAD; + AWT_ASSERT_APPKIT_THREAD; JNIEnv *env = [ThreadUtilities getJNIEnv]; -JNF_COCOA_ENTER(env); - + JNF_COCOA_ENTER(env); + // If we are called as a result of user pressing a shortcut, do nothing, // because AVTView has already sent corresponding key event to the Java // layer from performKeyEquivalent. @@ -82,31 +118,37 @@ JNF_COCOA_ENTER(env); NSEvent *currEvent = [[NSApplication sharedApplication] currentEvent]; if ([currEvent type] == NSKeyDown) { NSString *menuKey = [sender keyEquivalent]; - NSString *eventKey = [currEvent charactersIgnoringModifiers]; - - // Apple uses characters from private Unicode range for some of the - // keys, so we need to do the same translation here that we do - // for the regular key down events - if ([eventKey length] == 1) { - unichar origChar = [eventKey characterAtIndex:0]; - unichar newChar = NsCharToJavaChar(origChar, 0); - if (newChar == java_awt_event_KeyEvent_CHAR_UNDEFINED) { - newChar = origChar; - } - - eventKey = [NSString stringWithCharacters: &newChar length: 1]; - } - +// If shortcut is "Command Shift ," the menuKey gets the value "," +// But [currEvent charactersIgnoringModifiers]; returns "<" and not "," +// because the charactersIgnoreingModifiers does not ignore "Shift" +// So a shortcut like "Command Shift m" will return "M" where as the +// MenuKey will have the value "m". To remove this issue the below +// createStringForKey is used. + NSString *eventKey = createStringForKey([currEvent keyCode]); + +// Apple uses characters from private Unicode range for some of the +// keys, so we need to do the same translation here that we do +// for the regular key down events + if ([eventKey length] == 1) { + unichar origChar = [eventKey characterAtIndex:0]; + unichar newChar = NsCharToJavaChar(origChar, 0); + if (newChar == java_awt_event_KeyEvent_CHAR_UNDEFINED) { + newChar = origChar; + } + + eventKey = [NSString stringWithCharacters: &newChar length: 1]; + } + NSWindow *keyWindow = [NSApp keyWindow]; if ([menuKey isEqualToString:eventKey] && keyWindow != nil) { return; } } - + if (fIsCheckbox) { static JNF_CLASS_CACHE(jc_CCheckboxMenuItem, "sun/lwawt/macosx/CCheckboxMenuItem"); static JNF_MEMBER_CACHE(jm_ckHandleAction, jc_CCheckboxMenuItem, "handleAction", "(Z)V"); - + // Send the opposite of what's currently checked -- the action // indicates what state we're going to. NSInteger state = [sender state]; @@ -115,26 +157,26 @@ JNF_COCOA_ENTER(env); } else { static JNF_CLASS_CACHE(jc_CMenuItem, "sun/lwawt/macosx/CMenuItem"); static JNF_MEMBER_CACHE(jm_handleAction, jc_CMenuItem, "handleAction", "(JI)V"); // AWT_THREADING Safe (event) - + NSUInteger modifiers = [currEvent modifierFlags]; jint javaModifiers = NsKeyModifiersToJavaModifiers(modifiers, NO); - + JNFCallVoidMethod(env, fPeer, jm_handleAction, UTC(currEvent), javaModifiers); // AWT_THREADING Safe (event) } -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } - (void) setJavaLabel:(NSString *)theLabel shortcut:(NSString *)theKeyEquivalent modifierMask:(jint)modifiers { - + NSUInteger modifierMask = 0; - + if (![theKeyEquivalent isEqualToString:@""]) { // Force the key equivalent to lower case if not using the shift key. // Otherwise AppKit will draw a Shift glyph in the menu. if ((modifiers & java_awt_event_KeyEvent_SHIFT_MASK) == 0) { theKeyEquivalent = [theKeyEquivalent lowercaseString]; } - + // Hack for the question mark -- SHIFT and / means use the question mark. if ((modifiers & java_awt_event_KeyEvent_SHIFT_MASK) != 0 && [theKeyEquivalent isEqualToString:@"/"]) @@ -142,10 +184,10 @@ JNF_COCOA_EXIT(env); theKeyEquivalent = @"?"; modifiers &= ~java_awt_event_KeyEvent_SHIFT_MASK; } - + modifierMask = JavaModifiersToNsKeyModifiers(modifiers, NO); } - + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ [fMenuItem setKeyEquivalent:theKeyEquivalent]; [fMenuItem setKeyEquivalentModifierMask:modifierMask]; @@ -154,14 +196,14 @@ JNF_COCOA_EXIT(env); } - (void) setJavaImage:(NSImage *)theImage { - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [fMenuItem setImage:theImage]; }]; } - (void) setJavaToolTipText:(NSString *)theText { - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [fMenuItem setToolTip:theText]; }]; @@ -169,11 +211,11 @@ JNF_COCOA_EXIT(env); - (void)setJavaEnabled:(BOOL) enabled { - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ @synchronized(self) { fIsEnabled = enabled; - + // Warning: This won't work if the parent menu is disabled. // See [CMenu syncFromJava]. We still need to call it here so // the NSMenuItem itself gets properly updated. @@ -183,7 +225,7 @@ JNF_COCOA_EXIT(env); } - (BOOL)isEnabled { - + BOOL enabled = NO; @synchronized(self) { enabled = fIsEnabled; @@ -193,7 +235,7 @@ JNF_COCOA_EXIT(env); - (void)setJavaState:(BOOL)newState { - + [ThreadUtilities performOnMainThreadWaiting:NO block:^(){ [fMenuItem setState:(newState ? NSOnState : NSOffState)]; }]; @@ -207,7 +249,7 @@ JNF_COCOA_EXIT(env); - (void)dealloc { [fMenuItem release]; fMenuItem = nil; - + [super dealloc]; } @@ -240,7 +282,7 @@ JNF_COCOA_EXIT(env); /** Convert a Java keycode for SetMenuItemCmd */ static unichar AWTKeyToMacShortcut(jint awtKey, BOOL doShift) { unichar macKey = 0; - + if ((awtKey >= java_awt_event_KeyEvent_VK_0 && awtKey <= java_awt_event_KeyEvent_VK_9) || (awtKey >= java_awt_event_KeyEvent_VK_A && awtKey <= java_awt_event_KeyEvent_VK_Z)) { @@ -255,68 +297,68 @@ static unichar AWTKeyToMacShortcut(jint awtKey, BOOL doShift) { } else { // Special characters switch (awtKey) { - case java_awt_event_KeyEvent_VK_BACK_QUOTE : macKey = '`'; break; - case java_awt_event_KeyEvent_VK_QUOTE : macKey = '\''; break; - - case java_awt_event_KeyEvent_VK_ESCAPE : macKey = 0x1B; break; - case java_awt_event_KeyEvent_VK_SPACE : macKey = ' '; break; - case java_awt_event_KeyEvent_VK_PAGE_UP : macKey = NSPageUpFunctionKey; break; - case java_awt_event_KeyEvent_VK_PAGE_DOWN : macKey = NSPageDownFunctionKey; break; - case java_awt_event_KeyEvent_VK_END : macKey = NSEndFunctionKey; break; - case java_awt_event_KeyEvent_VK_HOME : macKey = NSHomeFunctionKey; break; - - case java_awt_event_KeyEvent_VK_LEFT : macKey = NSLeftArrowFunctionKey; break; - case java_awt_event_KeyEvent_VK_UP : macKey = NSUpArrowFunctionKey; break; - case java_awt_event_KeyEvent_VK_RIGHT : macKey = NSRightArrowFunctionKey; break; - case java_awt_event_KeyEvent_VK_DOWN : macKey = NSDownArrowFunctionKey; break; - - case java_awt_event_KeyEvent_VK_COMMA : macKey = ','; break; - - // Mac OS doesn't distinguish between the two '-' keys... - case java_awt_event_KeyEvent_VK_MINUS : - case java_awt_event_KeyEvent_VK_SUBTRACT : macKey = '-'; break; - - // or the two '.' keys... - case java_awt_event_KeyEvent_VK_DECIMAL : - case java_awt_event_KeyEvent_VK_PERIOD : macKey = '.'; break; - - // or the two '/' keys. - case java_awt_event_KeyEvent_VK_DIVIDE : - case java_awt_event_KeyEvent_VK_SLASH : macKey = '/'; break; - - case java_awt_event_KeyEvent_VK_SEMICOLON : macKey = ';'; break; - case java_awt_event_KeyEvent_VK_EQUALS : macKey = '='; break; - - case java_awt_event_KeyEvent_VK_OPEN_BRACKET : macKey = '['; break; - case java_awt_event_KeyEvent_VK_BACK_SLASH : macKey = '\\'; break; - case java_awt_event_KeyEvent_VK_CLOSE_BRACKET : macKey = ']'; break; - - case java_awt_event_KeyEvent_VK_MULTIPLY : macKey = '*'; break; - case java_awt_event_KeyEvent_VK_ADD : macKey = '+'; break; - - case java_awt_event_KeyEvent_VK_HELP : macKey = NSHelpFunctionKey; break; - case java_awt_event_KeyEvent_VK_TAB : macKey = NSTabCharacter; break; - case java_awt_event_KeyEvent_VK_ENTER : macKey = NSNewlineCharacter; break; - case java_awt_event_KeyEvent_VK_BACK_SPACE : macKey = NSBackspaceCharacter; break; - case java_awt_event_KeyEvent_VK_DELETE : macKey = NSDeleteCharacter; break; - case java_awt_event_KeyEvent_VK_CLEAR : macKey = NSClearDisplayFunctionKey; break; - case java_awt_event_KeyEvent_VK_AMPERSAND : macKey = '&'; break; - case java_awt_event_KeyEvent_VK_ASTERISK : macKey = '*'; break; - case java_awt_event_KeyEvent_VK_QUOTEDBL : macKey = '\"'; break; - case java_awt_event_KeyEvent_VK_LESS : macKey = '<'; break; - case java_awt_event_KeyEvent_VK_GREATER : macKey = '>'; break; - case java_awt_event_KeyEvent_VK_BRACELEFT : macKey = '{'; break; - case java_awt_event_KeyEvent_VK_BRACERIGHT : macKey = '}'; break; - case java_awt_event_KeyEvent_VK_AT : macKey = '@'; break; - case java_awt_event_KeyEvent_VK_COLON : macKey = ':'; break; - case java_awt_event_KeyEvent_VK_CIRCUMFLEX : macKey = '^'; break; - case java_awt_event_KeyEvent_VK_DOLLAR : macKey = '$'; break; - case java_awt_event_KeyEvent_VK_EXCLAMATION_MARK : macKey = '!'; break; - case java_awt_event_KeyEvent_VK_LEFT_PARENTHESIS : macKey = '('; break; - case java_awt_event_KeyEvent_VK_NUMBER_SIGN : macKey = '#'; break; - case java_awt_event_KeyEvent_VK_PLUS : macKey = '+'; break; - case java_awt_event_KeyEvent_VK_RIGHT_PARENTHESIS: macKey = ')'; break; - case java_awt_event_KeyEvent_VK_UNDERSCORE : macKey = '_'; break; + case java_awt_event_KeyEvent_VK_BACK_QUOTE : macKey = '`'; break; + case java_awt_event_KeyEvent_VK_QUOTE : macKey = '\''; break; + + case java_awt_event_KeyEvent_VK_ESCAPE : macKey = 0x1B; break; + case java_awt_event_KeyEvent_VK_SPACE : macKey = ' '; break; + case java_awt_event_KeyEvent_VK_PAGE_UP : macKey = NSPageUpFunctionKey; break; + case java_awt_event_KeyEvent_VK_PAGE_DOWN : macKey = NSPageDownFunctionKey; break; + case java_awt_event_KeyEvent_VK_END : macKey = NSEndFunctionKey; break; + case java_awt_event_KeyEvent_VK_HOME : macKey = NSHomeFunctionKey; break; + + case java_awt_event_KeyEvent_VK_LEFT : macKey = NSLeftArrowFunctionKey; break; + case java_awt_event_KeyEvent_VK_UP : macKey = NSUpArrowFunctionKey; break; + case java_awt_event_KeyEvent_VK_RIGHT : macKey = NSRightArrowFunctionKey; break; + case java_awt_event_KeyEvent_VK_DOWN : macKey = NSDownArrowFunctionKey; break; + + case java_awt_event_KeyEvent_VK_COMMA : macKey = ','; break; + + // Mac OS doesn't distinguish between the two '-' keys... + case java_awt_event_KeyEvent_VK_MINUS : + case java_awt_event_KeyEvent_VK_SUBTRACT : macKey = '-'; break; + + // or the two '.' keys... + case java_awt_event_KeyEvent_VK_DECIMAL : + case java_awt_event_KeyEvent_VK_PERIOD : macKey = '.'; break; + + // or the two '/' keys. + case java_awt_event_KeyEvent_VK_DIVIDE : + case java_awt_event_KeyEvent_VK_SLASH : macKey = '/'; break; + + case java_awt_event_KeyEvent_VK_SEMICOLON : macKey = ';'; break; + case java_awt_event_KeyEvent_VK_EQUALS : macKey = '='; break; + + case java_awt_event_KeyEvent_VK_OPEN_BRACKET : macKey = '['; break; + case java_awt_event_KeyEvent_VK_BACK_SLASH : macKey = '\\'; break; + case java_awt_event_KeyEvent_VK_CLOSE_BRACKET : macKey = ']'; break; + + case java_awt_event_KeyEvent_VK_MULTIPLY : macKey = '*'; break; + case java_awt_event_KeyEvent_VK_ADD : macKey = '+'; break; + + case java_awt_event_KeyEvent_VK_HELP : macKey = NSHelpFunctionKey; break; + case java_awt_event_KeyEvent_VK_TAB : macKey = NSTabCharacter; break; + case java_awt_event_KeyEvent_VK_ENTER : macKey = NSNewlineCharacter; break; + case java_awt_event_KeyEvent_VK_BACK_SPACE : macKey = NSBackspaceCharacter; break; + case java_awt_event_KeyEvent_VK_DELETE : macKey = NSDeleteCharacter; break; + case java_awt_event_KeyEvent_VK_CLEAR : macKey = NSClearDisplayFunctionKey; break; + case java_awt_event_KeyEvent_VK_AMPERSAND : macKey = '&'; break; + case java_awt_event_KeyEvent_VK_ASTERISK : macKey = '*'; break; + case java_awt_event_KeyEvent_VK_QUOTEDBL : macKey = '\"'; break; + case java_awt_event_KeyEvent_VK_LESS : macKey = '<'; break; + case java_awt_event_KeyEvent_VK_GREATER : macKey = '>'; break; + case java_awt_event_KeyEvent_VK_BRACELEFT : macKey = '{'; break; + case java_awt_event_KeyEvent_VK_BRACERIGHT : macKey = '}'; break; + case java_awt_event_KeyEvent_VK_AT : macKey = '@'; break; + case java_awt_event_KeyEvent_VK_COLON : macKey = ':'; break; + case java_awt_event_KeyEvent_VK_CIRCUMFLEX : macKey = '^'; break; + case java_awt_event_KeyEvent_VK_DOLLAR : macKey = '$'; break; + case java_awt_event_KeyEvent_VK_EXCLAMATION_MARK : macKey = '!'; break; + case java_awt_event_KeyEvent_VK_LEFT_PARENTHESIS : macKey = '('; break; + case java_awt_event_KeyEvent_VK_NUMBER_SIGN : macKey = '#'; break; + case java_awt_event_KeyEvent_VK_PLUS : macKey = '+'; break; + case java_awt_event_KeyEvent_VK_RIGHT_PARENTHESIS: macKey = ')'; break; + case java_awt_event_KeyEvent_VK_UNDERSCORE : macKey = '_'; break; } } return macKey; @@ -330,27 +372,27 @@ static unichar AWTKeyToMacShortcut(jint awtKey, BOOL doShift) { JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CMenuItem_nativeSetLabel (JNIEnv *env, jobject peer, - jlong menuItemObj, jstring label, - jchar shortcutKey, jint shortcutKeyCode, jint mods) + jlong menuItemObj, jstring label, + jchar shortcutKey, jint shortcutKeyCode, jint mods) { -JNF_COCOA_ENTER(env); + JNF_COCOA_ENTER(env); NSString *theLabel = JNFJavaToNSString(env, label); NSString *theKeyEquivalent = nil; unichar macKey = shortcutKey; - + if (macKey == 0) { macKey = AWTKeyToMacShortcut(shortcutKeyCode, (mods & java_awt_event_KeyEvent_SHIFT_MASK) != 0); } - + if (macKey != 0) { unichar equivalent[1] = {macKey}; theKeyEquivalent = [NSString stringWithCharacters:equivalent length:1]; } else { theKeyEquivalent = @""; } - + [((CMenuItem *)jlong_to_ptr(menuItemObj)) setJavaLabel:theLabel shortcut:theKeyEquivalent modifierMask:mods]; -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } /* @@ -362,10 +404,10 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CMenuItem_nativeSetTooltip (JNIEnv *env, jobject peer, jlong menuItemObj, jstring tooltip) { -JNF_COCOA_ENTER(env); + JNF_COCOA_ENTER(env); NSString *theTooltip = JNFJavaToNSString(env, tooltip); [((CMenuItem *)jlong_to_ptr(menuItemObj)) setJavaToolTipText:theTooltip]; -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } /* @@ -377,9 +419,9 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CMenuItem_nativeSetImage (JNIEnv *env, jobject peer, jlong menuItemObj, jlong image) { -JNF_COCOA_ENTER(env); + JNF_COCOA_ENTER(env); [((CMenuItem *)jlong_to_ptr(menuItemObj)) setJavaImage:(NSImage*)jlong_to_ptr(image)]; -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } /* @@ -389,38 +431,38 @@ JNF_COCOA_EXIT(env); */ JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CMenuItem_nativeCreate - (JNIEnv *env, jobject peer, jlong parentCMenuObj, jboolean isSeparator) +(JNIEnv *env, jobject peer, jlong parentCMenuObj, jboolean isSeparator) { - + CMenuItem *aCMenuItem = nil; CMenu *parentCMenu = (CMenu *)jlong_to_ptr(parentCMenuObj); -JNF_COCOA_ENTER(env); - + JNF_COCOA_ENTER(env); + jobject cPeerObjGlobal = (*env)->NewGlobalRef(env, peer); - + NSMutableArray *args = nil; - + // Create a new item.... if (isSeparator == JNI_TRUE) { args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], [NSNumber numberWithBool:YES], nil]; } else { args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], [NSNumber numberWithBool:NO], nil]; } - + [ThreadUtilities performOnMainThread:@selector(_createMenuItem_OnAppKitThread:) on:[CMenuItem alloc] withObject:args waitUntilDone:YES]; - + aCMenuItem = (CMenuItem *)[args objectAtIndex: 0]; - + if (aCMenuItem == nil) { return 0L; } - + // and add it to the parent item. [parentCMenu addJavaMenuItem: aCMenuItem]; - + // setLabel will be called after creation completes. - -JNF_COCOA_EXIT(env); + + JNF_COCOA_EXIT(env); return ptr_to_jlong(aCMenuItem); } @@ -433,10 +475,10 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CMenuItem_nativeSetEnabled (JNIEnv *env, jobject peer, jlong menuItemObj, jboolean enable) { -JNF_COCOA_ENTER(env); + JNF_COCOA_ENTER(env); CMenuItem *item = (CMenuItem *)jlong_to_ptr(menuItemObj); [item setJavaEnabled: (enable == JNI_TRUE)]; -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } /* @@ -448,10 +490,10 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CCheckboxMenuItem_nativeSetState (JNIEnv *env, jobject peer, jlong menuItemObj, jboolean state) { -JNF_COCOA_ENTER(env); + JNF_COCOA_ENTER(env); CMenuItem *item = (CMenuItem *)jlong_to_ptr(menuItemObj); [item setJavaState: (state == JNI_TRUE)]; -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } /* @@ -463,8 +505,8 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CCheckboxMenuItem_nativeSetIsCheckbox (JNIEnv *env, jobject peer, jlong menuItemObj) { -JNF_COCOA_ENTER(env); + JNF_COCOA_ENTER(env); CMenuItem *item = (CMenuItem *)jlong_to_ptr(menuItemObj); [item setIsCheckbox]; -JNF_COCOA_EXIT(env); + JNF_COCOA_EXIT(env); } diff --git a/jdk/test/javax/swing/JMenuItem/8139169/ScreenMenuBarInputTwice.java b/jdk/test/javax/swing/JMenuItem/8139169/ScreenMenuBarInputTwice.java new file mode 100644 index 00000000000..b591e6bc585 --- /dev/null +++ b/jdk/test/javax/swing/JMenuItem/8139169/ScreenMenuBarInputTwice.java @@ -0,0 +1,234 @@ +/* + * 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 8139169 + * @summary verifies if TextArea gets input twice due to Apple's Screen Menubar + * @requires (os.family=="mac") + * @library ../../regtesthelpers + * @build Util + * @run main ScreenMenuBarInputTwice + */ +import java.awt.BorderLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import static java.awt.event.KeyEvent.VK_COMMA; +import static java.awt.event.KeyEvent.VK_META; +import static java.awt.event.KeyEvent.VK_SHIFT; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; + +public class ScreenMenuBarInputTwice { + + public static final String TEST_STRING = "Check string"; + + private static Robot robot; + private static JFrame frame; + private static JPanel content; + private static JTextArea textArea; + private static JMenuBar menuBar; + private static JMenu menu; + private static JMenuItem menuItem; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + createUIWithSeperateMenuBar(); + robot.delay(2000); + shortcutTestCase(); + robot.delay(2000); + cleanUp(); + createUIWithIntegratedMenuBar(); + robot.delay(2000); + menuTestCase(); + robot.delay(2000); + cleanUp(); + } + + private static void createUIWithSeperateMenuBar() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + System.setProperty( + "com.apple.mrj.application.apple.menu.about.name", + "A test frame"); + System.setProperty("apple.laf.useScreenMenuBar", "true"); + frame = new JFrame("Text input twice check"); + content = new JPanel(new BorderLayout()); + textArea = new JTextArea(); + content.add(new JScrollPane(textArea, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), + BorderLayout.CENTER); + menuBar = new JMenuBar(); + frame.setJMenuBar(menuBar); + Action a = new AbstractAction("Insert some text") { + @Override + public void actionPerformed(ActionEvent arg0) { + try { + + textArea.getDocument() + .insertString(0, TEST_STRING, null); + } catch (BadLocationException e) { + frame.dispose(); + throw new RuntimeException("Bad location: ", e); + } + } + }; + KeyStroke keyStroke = KeyStroke.getKeyStroke( + "meta shift COMMA"); + a.putValue(Action.ACCELERATOR_KEY, keyStroke); + textArea.getInputMap().put(keyStroke, "myAction"); + textArea.getActionMap().put("myAction", a); + menu = new JMenu("The Menu"); + menuItem = new JMenuItem(a); + menuItem.setAccelerator((KeyStroke) a.getValue( + Action.ACCELERATOR_KEY)); + menu.add(menuItem); + menuBar.add(menu); + frame.getContentPane().add(content); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setLocationRelativeTo(null); + frame.setSize(500, 500); + frame.setVisible(true); + frame.toFront(); + } + }); + } + + private static void createUIWithIntegratedMenuBar() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + System.setProperty( + "com.apple.mrj.application.apple.menu.about.name", + "A test frame"); + System.setProperty("apple.laf.useScreenMenuBar", "false"); + frame = new JFrame("Text input twice check"); + content = new JPanel(new BorderLayout()); + textArea = new JTextArea(); + content.add(new JScrollPane(textArea, + JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), + BorderLayout.CENTER); + menuBar = new JMenuBar(); + frame.setJMenuBar(menuBar); + Action a = new AbstractAction("Insert some text") { + @Override + public void actionPerformed(ActionEvent arg0) { + try { + + textArea.getDocument() + .insertString(0, TEST_STRING, null); + } catch (BadLocationException e) { + frame.dispose(); + throw new RuntimeException("Bad location: ", e); + } + } + }; + KeyStroke keyStroke = KeyStroke.getKeyStroke( + "meta shift COMMA"); + a.putValue(Action.ACCELERATOR_KEY, keyStroke); + textArea.getInputMap().put(keyStroke, "myAction"); + textArea.getActionMap().put("myAction", a); + menu = new JMenu("The Menu"); + menuItem = new JMenuItem(a); + menuItem.setAccelerator((KeyStroke) a.getValue( + Action.ACCELERATOR_KEY)); + menu.add(menuItem); + menuBar.add(menu); + frame.getContentPane().add(content); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(500, 500); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.toFront(); + } + }); + } + + private static void shortcutTestCase() throws Exception { + robot.keyPress(KeyEvent.VK_META); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_COMMA); + robot.keyRelease(VK_COMMA); + robot.keyRelease(VK_SHIFT); + robot.keyRelease(VK_META); + robot.delay(2000); + checkText(textArea.getText()); + } + + private static void menuTestCase() throws Exception { + Point mousePoint; + mousePoint = Util.getCenterPoint(menu); + robot.mouseMove(mousePoint.x, mousePoint.y); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.delay(2000); + mousePoint = Util.getCenterPoint(menuItem); + robot.mouseMove(mousePoint.x, mousePoint.y); + robot.delay(2000); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.delay(2000); + checkText(textArea.getText()); + } + + private static void checkText(String text) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + if (TEST_STRING.equals(text)) { + textArea.setText(""); + } else { + frame.dispose(); + throw new RuntimeException("Failed. " + + " Menu item shortcut invoked twice"); + } + } + }); + } + + private static void cleanUp() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame.dispose(); + } + }); + } +} From 946e0bc9cc01c228cb3c9a6b86aa145904788b04 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 10 Dec 2015 16:09:42 +0300 Subject: [PATCH 069/215] 8040139: Test closed/javax/print/attribute/Services_getDocFl.java fails with NullpointerException Reviewed-by: jdv, prr --- .../classes/sun/print/IPPPrintService.java | 5 +- .../print/attribute/Services_getDocFl.java | 84 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 jdk/test/javax/print/attribute/Services_getDocFl.java diff --git a/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java b/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java index 7782d543219..9587067a750 100644 --- a/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java +++ b/jdk/src/java.desktop/unix/classes/sun/print/IPPPrintService.java @@ -926,7 +926,10 @@ public class IPPPrintService implements PrintService, SunPrinterJobService { return copyflavors; } } - return null; + DocFlavor[] flavor = new DocFlavor[2]; + flavor[0] = DocFlavor.SERVICE_FORMATTED.PAGEABLE; + flavor[1] = DocFlavor.SERVICE_FORMATTED.PRINTABLE; + return flavor; } diff --git a/jdk/test/javax/print/attribute/Services_getDocFl.java b/jdk/test/javax/print/attribute/Services_getDocFl.java new file mode 100644 index 00000000000..e3f0a850e3f --- /dev/null +++ b/jdk/test/javax/print/attribute/Services_getDocFl.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +import javax.print.DocFlavor; +import javax.print.PrintService; +import javax.print.PrintServiceLookup; +import javax.print.attribute.HashPrintRequestAttributeSet; + +/* + * @test + * @bug 4901243 8040139 + * @summary JPG, GIF, and PNG DocFlavors (URL) should be supported if Postscript is supported. + * @run main Services_getDocFl +*/ + + +public class Services_getDocFl { + public static void main (String [] args) { + + HashPrintRequestAttributeSet prSet = null; + boolean psSupported = false, + pngImagesSupported = false, + gifImagesSupported = false, + jpgImagesSupported = false; + String mimeType; + + PrintService[] serv = PrintServiceLookup.lookupPrintServices(null, null); + if (serv.length==0) { + System.out.println("no PrintService found"); + } else { + System.out.println("number of Services "+serv.length); + } + + + for (int i = 0; i Date: Thu, 10 Dec 2015 12:16:29 -0600 Subject: [PATCH 070/215] 8071334: Investigate JAB changes required to support the version string change Remove use of java.version property; no longer needed Reviewed-by: van, alexsch --- .../accessibility/util/AWTEventMonitor.java | 20 ++----------------- .../accessibility/internal/AccessBridge.java | 10 ++-------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java index 7b0f8c29e06..257bbb72953 100644 --- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java @@ -48,8 +48,6 @@ import sun.awt.AWTPermissions; @jdk.Exported public class AWTEventMonitor { - static private boolean runningOnJDK1_4 = false; - /** * The current component with keyboard focus. * @@ -638,15 +636,9 @@ public class AWTEventMonitor { * @see AWTEventMonitor */ public AWTEventsListener() { - String version = System.getProperty("java.version"); - if (version != null) { - runningOnJDK1_4 = (version.compareTo("1.4") >= 0); - } initializeIntrospection(); installListeners(); - if (runningOnJDK1_4) { - MenuSelectionManager.defaultManager().addChangeListener(this); - } + MenuSelectionManager.defaultManager().addChangeListener(this); EventQueueMonitor.addTopLevelWindowListener(this); } @@ -848,15 +840,7 @@ public class AWTEventMonitor { case EventID.FOCUS: c.removeFocusListener(this); c.addFocusListener(this); - - if (runningOnJDK1_4) { - processFocusGained(); - - } else { // not runningOnJDK1_4 - if ((c != componentWithFocus_private) && c.hasFocus()) { - componentWithFocus_private = c; - } - } + processFocusGained(); break; case EventID.ITEM: diff --git a/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java b/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java index ee1a63f5ec9..47832a4455b 100644 --- a/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java +++ b/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java @@ -140,10 +140,6 @@ final public class AccessBridge { // initialize AccessibleRole map initAccessibleRoleMap(); - // determine which version of the JDK is running - String version = getJavaVersionProperty(); - debugString("JDK version = "+version); - // initialize the methods that map HWNDs and Java top-level // windows initHWNDcalls(); @@ -215,9 +211,7 @@ final public class AccessBridge { } catch (Exception e) {} /* - Build the extendedVirtualNameSearchRoles array list. I chose this method - because some of the Accessible Roles that need to be added to it are not - available in all versions of the J2SE that we want to support. + Build the extendedVirtualNameSearchRoles array list. */ extendedVirtualNameSearchRoles.add (AccessibleRole.COMBO_BOX); try { @@ -5919,7 +5913,7 @@ final public class AccessBridge { */ AccessibleRole.UNKNOWN, - // These roles are only available in JDK 1.4 + // These roles are available since JDK 1.4 /** * A STATUS_BAR is an simple component that can contain From c588dd42dd368d2ef8b6350ec6766c5837c3b39a Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 10 Dec 2015 12:51:08 -0800 Subject: [PATCH 071/215] 8144858: HBShaper.c does not compiler with VS2010 Reviewed-by: serb, simonis --- .../share/native/libfontmanager/HBShaper.c | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c b/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c index 422575cb165..00c6ee1fa44 100644 --- a/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c +++ b/jdk/src/java.desktop/share/native/libfontmanager/HBShaper.c @@ -80,15 +80,18 @@ int storeGVData(JNIEnv* env, float scale = 1.0f/64.0f; unsigned int* glyphs; float* positions; + int initialCount, glyphArrayLen, posArrayLen, maxGlyphs, storeadv; + unsigned int* indices; + jarray glyphArray, posArray, inxArray; if (!init_JNI_IDs(env)) { return 0; } - int initialCount = (*env)->GetIntField(env, gvdata, gvdCountFID); - jarray glyphArray = + initialCount = (*env)->GetIntField(env, gvdata, gvdCountFID); + glyphArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdGlyphsFID); - jarray posArray = + posArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdPositionsFID); if (glyphArray == NULL || posArray == NULL) @@ -101,9 +104,9 @@ int storeGVData(JNIEnv* env, // and re-invokes layout. I suppose this is expected to be rare // because at least in a single threaded case there should be // re-use of the same container, but it is a little wasteful/distateful. - int glyphArrayLen = (*env)->GetArrayLength(env, glyphArray); - int posArrayLen = (*env)->GetArrayLength(env, posArray); - int maxGlyphs = glyphCount + initialCount; + glyphArrayLen = (*env)->GetArrayLength(env, glyphArray); + posArrayLen = (*env)->GetArrayLength(env, posArray); + maxGlyphs = glyphCount + initialCount; if ((maxGlyphs > glyphArrayLen) || (maxGlyphs * 2 + 2 > posArrayLen)) { @@ -125,7 +128,7 @@ int storeGVData(JNIEnv* env, x += glyphPos[i].x_advance * scale; y += glyphPos[i].y_advance * scale; } - int storeadv = initialCount+glyphCount; + storeadv = initialCount+glyphCount; // The final slot in the positions array is important // because when the GlyphVector is created from this // data it determines the overall advance of the glyphvector @@ -138,11 +141,10 @@ int storeGVData(JNIEnv* env, (*env)->ReleasePrimitiveArrayCritical(env, glyphArray, glyphs, 0); (*env)->ReleasePrimitiveArrayCritical(env, posArray, positions, 0); putFloat(env, startPt,positions[(storeadv*2)],positions[(storeadv*2)+1] ); - jarray inxArray = + inxArray = (jarray)(*env)->GetObjectField(env, gvdata, gvdIndicesFID); - unsigned int* indices = + indices = (unsigned int*)(*env)->GetPrimitiveArrayCritical(env, inxArray, NULL); - int prevCluster = -1; for (i = 0; i < glyphCount; i++) { int cluster = glyphInfo[i].cluster; if (direction == HB_DIRECTION_LTR) { From bb10c3f0de78a4672b09296c90d3e54fe5fd22ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Bourg=C3=A8s?= Date: Thu, 10 Dec 2015 15:45:18 -0800 Subject: [PATCH 072/215] 8144446: Automate the Marlin crash test Reviewed-by: prr, flar --- .../classes/sun/java2d/marlin/Renderer.java | 7 +++ jdk/test/sun/java2d/marlin/CrashTest.java | 59 ++++++++++--------- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java index d4aa005eadb..f59785cd92f 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java @@ -629,6 +629,13 @@ final class Renderer implements PathConsumer2D, MarlinConst { } if (edgeMinY != Float.POSITIVE_INFINITY) { + // if context is maked as DIRTY: + if (rdrCtx.dirty) { + // may happen if an exception if thrown in the pipeline processing: + // clear completely buckets arrays: + buckets_minY = 0; + buckets_maxY = boundsMaxY - boundsMinY; + } // clear used part if (edgeBuckets == edgeBuckets_initial) { // fill only used part diff --git a/jdk/test/sun/java2d/marlin/CrashTest.java b/jdk/test/sun/java2d/marlin/CrashTest.java index b5f760a65e3..b5283fdf332 100644 --- a/jdk/test/sun/java2d/marlin/CrashTest.java +++ b/jdk/test/sun/java2d/marlin/CrashTest.java @@ -31,31 +31,44 @@ import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; -import sun.java2d.pipe.RenderingEngine; /** - * Simple crash rendering test using huge GeneralPaths with marlin renderer - * - * run it with large heap (2g): - * java -Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine marlin.CrashTest - * - * @author bourgesl - */ + * @test + * @summary Simple crash rendering test using huge GeneralPaths with the Marlin renderer + * @run main/othervm -mx512m CrashTest + * @ignore tests that take a long time and consumes 5Gb memory + * @run main/othervm -ms4g -mx4g CrashTest -slow +*/ public class CrashTest { static final boolean SAVE_IMAGE = false; static boolean USE_ROUND_CAPS_AND_JOINS = true; public static void main(String[] args) { + boolean runSlowTests = (args.length != 0 && "-slow".equals(args[0])); + + // First display which renderer is tested: + System.setProperty("sun.java2d.renderer.verbose", "true"); + // try insane image sizes: // subpixel coords may overflow: -// testHugeImage((Integer.MAX_VALUE >> 3) + 1, 6); + // check MAX_VALUE / (8 * 2); overflow may happen due to orientation flag + // But as it is impossible to allocate an image larger than 2Gb (byte) then + // it is also impossible to have rowAAChunk larger than 2Gb ! + + // Disabled test as it consumes 4GB heap + offheap (2Gb) ie > 6Gb ! + if (runSlowTests) { + testHugeImage((Integer.MAX_VALUE >> 4) - 100, 16); + } + // larger than 23 bits: (RLE) testHugeImage(8388608 + 1, 10); - test(0.1f, false, 0); - test(0.1f, true, 7f); + if (runSlowTests) { + test(0.1f, false, 0); + test(0.1f, true, 7f); + } // Exceed 2Gb OffHeap buffer for edges: try { @@ -67,17 +80,15 @@ public class CrashTest { if (th instanceof ArrayIndexOutOfBoundsException) { System.out.println("ArrayIndexOutOfBoundsException expected."); } else { - System.out.println("Exception occured:"); - th.printStackTrace(); + throw new RuntimeException("Unexpected exception", th); } } - } private static void test(final float lineStroke, final boolean useDashes, final float dashMinLen) - throws ArrayIndexOutOfBoundsException + throws ArrayIndexOutOfBoundsException { System.out.println("---\n" + "test: " + "lineStroke=" + lineStroke @@ -85,9 +96,6 @@ public class CrashTest { +", dashMinLen=" + dashMinLen ); - final String renderer = RenderingEngine.getInstance().getClass().getSimpleName(); - System.out.println("Testing renderer = " + renderer); - final BasicStroke stroke = createStroke(lineStroke, useDashes, dashMinLen); // TODO: test Dasher.firstSegmentsBuffer resizing ? @@ -135,7 +143,7 @@ public class CrashTest { if (SAVE_IMAGE) { try { - final File file = new File("CrashTest-" + renderer + "-dash-" + useDashes + ".bmp"); + final File file = new File("CrashTest-dash-" + useDashes + ".bmp"); System.out.println("Writing file: " + file.getAbsolutePath()); ImageIO.write(image, "BMP", file); @@ -150,15 +158,10 @@ public class CrashTest { } private static void testHugeImage(final int width, final int height) - throws ArrayIndexOutOfBoundsException + throws ArrayIndexOutOfBoundsException { System.out.println("---\n" + "testHugeImage: " - + "width=" + width - + ", height=" + height - ); - - final String renderer = RenderingEngine.getInstance().getClass().getSimpleName(); - System.out.println("Testing renderer = " + renderer); + + "width=" + width + ", height=" + height); final BasicStroke stroke = createStroke(2.5f, false, 0); @@ -195,8 +198,8 @@ public class CrashTest { if (SAVE_IMAGE) { try { - final File file = new File("CrashTest-" + renderer + - "-huge-" + width + "x" +height + ".bmp"); + final File file = new File("CrashTest-huge-" + + width + "x" +height + ".bmp"); System.out.println("Writing file: " + file.getAbsolutePath()); ImageIO.write(image, "BMP", file); From 80222f5b67383332c7c7ba63eaa6f40bbc30181f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Bourg=C3=A8s?= Date: Thu, 10 Dec 2015 15:52:14 -0800 Subject: [PATCH 073/215] 8144445: Maximum size checking in Marlin ArrayCache utility methods is not optimal Reviewed-by: prr, flar --- .../classes/sun/java2d/marlin/ArrayCache.java | 38 +++-- .../classes/sun/java2d/marlin/Stroker.java | 5 +- .../sun/java2d/marlin/ArrayCacheSizeTest.java | 131 ++++++++++++++++++ 3 files changed, 161 insertions(+), 13 deletions(-) create mode 100644 jdk/test/sun/java2d/marlin/ArrayCacheSizeTest.java diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ArrayCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ArrayCache.java index bc4bc54d0d5..e518c4d2261 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ArrayCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ArrayCache.java @@ -166,18 +166,31 @@ public final class ArrayCache implements MarlinConst { * @return new array size */ public static int getNewSize(final int curSize, final int needSize) { + // check if needSize is negative or integer overflow: + if (needSize < 0) { + // hard overflow failure - we can't even accommodate + // new items without overflowing + throw new ArrayIndexOutOfBoundsException( + "array exceeds maximum capacity !"); + } + assert curSize >= 0; final int initial = (curSize & MASK_CLR_1); int size; if (initial > THRESHOLD_ARRAY_SIZE) { size = initial + (initial >> 1); // x(3/2) } else { - size = (initial) << 1; // x2 + size = (initial << 1); // x2 } // ensure the new size is >= needed size: if (size < needSize) { - // align to 4096: + // align to 4096 (may overflow): size = ((needSize >> 12) + 1) << 12; } + // check integer overflow: + if (size < 0) { + // resize to maximum capacity: + size = Integer.MAX_VALUE; + } return size; } @@ -188,26 +201,29 @@ public final class ArrayCache implements MarlinConst { * @return new array size */ public static long getNewLargeSize(final long curSize, final long needSize) { + // check if needSize is negative or integer overflow: + if ((needSize >> 31L) != 0L) { + // hard overflow failure - we can't even accommodate + // new items without overflowing + throw new ArrayIndexOutOfBoundsException( + "array exceeds maximum capacity !"); + } + assert curSize >= 0L; long size; if (curSize > THRESHOLD_HUGE_ARRAY_SIZE) { size = curSize + (curSize >> 2L); // x(5/4) } else if (curSize > THRESHOLD_LARGE_ARRAY_SIZE) { size = curSize + (curSize >> 1L); // x(3/2) } else { - size = curSize << 1L; // x2 + size = (curSize << 1L); // x2 } // ensure the new size is >= needed size: if (size < needSize) { // align to 4096: - size = ((needSize >> 12) + 1) << 12; + size = ((needSize >> 12L) + 1L) << 12L; } - if (size >= Integer.MAX_VALUE) { - if (curSize >= Integer.MAX_VALUE) { - // hard overflow failure - we can't even accommodate - // new items without overflowing - throw new ArrayIndexOutOfBoundsException( - "array exceeds maximum capacity !"); - } + // check integer overflow: + if (size > Integer.MAX_VALUE) { // resize to maximum capacity: size = Integer.MAX_VALUE; } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java index 76c93494d57..1aa48411f04 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java @@ -1265,14 +1265,15 @@ final class Stroker implements PathConsumer2D, MarlinConst { } private void ensureSpace(final int n) { - if (end + n > curves.length) { + // use substraction to avoid integer overflow: + if (curves.length - end < n) { if (doStats) { RendererContext.stats.stat_array_stroker_polystack_curves .add(end + n); } curves = rdrCtx.widenDirtyFloatArray(curves, end, end + n); } - if (numCurves + 1 > curveTypes.length) { + if (curveTypes.length <= numCurves) { if (doStats) { RendererContext.stats.stat_array_stroker_polystack_curveTypes .add(numCurves + 1); diff --git a/jdk/test/sun/java2d/marlin/ArrayCacheSizeTest.java b/jdk/test/sun/java2d/marlin/ArrayCacheSizeTest.java new file mode 100644 index 00000000000..8c40fe4cfae --- /dev/null +++ b/jdk/test/sun/java2d/marlin/ArrayCacheSizeTest.java @@ -0,0 +1,131 @@ +/* + * 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. + */ + +import sun.java2d.marlin.ArrayCache; + +/** + * @test + * @bug 8144445 + * @summary Check the ArrayCache getNewLargeSize() method + * @run main ArrayCacheSizeTest + */ +public class ArrayCacheSizeTest { + + public static void main(String[] args) { + testNewSize(); + testNewLargeSize(); + } + + private static void testNewSize() { + testNewSize(0, 1); + testNewSize(0, 100000); + + testNewSize(4096, 4097); + testNewSize(4096 * 16, 4096 * 16 + 1); + + testNewSize(4096 * 4096 * 4, 4096 * 4096 * 4 + 1); + + testNewSize(4096 * 4096 * 4, Integer.MAX_VALUE); + + testNewSize(Integer.MAX_VALUE - 1000, Integer.MAX_VALUE); + + testNewSizeExpectAIOB(Integer.MAX_VALUE - 1000, Integer.MAX_VALUE + 1); + testNewSizeExpectAIOB(1, -1); + testNewSizeExpectAIOB(Integer.MAX_VALUE, -1); + } + + private static void testNewSizeExpectAIOB(final int curSize, + final int needSize) { + try { + testNewSize(curSize, needSize); + throw new RuntimeException("ArrayIndexOutOfBoundsException not thrown"); + } catch (ArrayIndexOutOfBoundsException aiobe) { + System.out.println("ArrayIndexOutOfBoundsException expected."); + } catch (RuntimeException re) { + throw re; + } catch (Throwable th) { + throw new RuntimeException("Unexpected exception", th); + } + } + + private static void testNewSize(final int curSize, + final int needSize) { + + int size = ArrayCache.getNewSize(curSize, needSize); + + System.out.println("getNewSize(" + curSize + ", " + needSize + + ") = " + size); + + if (size < 0 || size < needSize) { + throw new IllegalStateException("Invalid getNewSize(" + + curSize + ", " + needSize + ") = " + size + " !"); + } + } + + private static void testNewLargeSize() { + testNewLargeSize(0, 1); + testNewLargeSize(0, 100000); + + testNewLargeSize(4096, 4097); + testNewLargeSize(4096 * 16, 4096 * 16 + 1); + + testNewLargeSize(4096 * 4096 * 4, 4096 * 4096 * 4 + 1); + + testNewLargeSize(4096 * 4096 * 4, Integer.MAX_VALUE); + + testNewLargeSize(Integer.MAX_VALUE - 1000, Integer.MAX_VALUE); + + testNewLargeSizeExpectAIOB(Integer.MAX_VALUE - 1000, Integer.MAX_VALUE + 1L); + testNewLargeSizeExpectAIOB(1, -1L); + testNewLargeSizeExpectAIOB(Integer.MAX_VALUE, -1L); + } + + private static void testNewLargeSizeExpectAIOB(final long curSize, + final long needSize) { + try { + testNewLargeSize(curSize, needSize); + throw new RuntimeException("ArrayIndexOutOfBoundsException not thrown"); + } catch (ArrayIndexOutOfBoundsException aiobe) { + System.out.println("ArrayIndexOutOfBoundsException expected."); + } catch (RuntimeException re) { + throw re; + } catch (Throwable th) { + throw new RuntimeException("Unexpected exception", th); + } + } + + private static void testNewLargeSize(final long curSize, + final long needSize) { + + long size = ArrayCache.getNewLargeSize(curSize, needSize); + + System.out.println("getNewLargeSize(" + curSize + ", " + needSize + + ") = " + size); + + if (size < 0 || size < needSize || size > Integer.MAX_VALUE) { + throw new IllegalStateException("Invalid getNewLargeSize(" + + curSize + ", " + needSize + ") = " + size + " !"); + } + } + +} From 583937011af76bd244566791f598991fbd7cd995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20Bourg=C3=A8s?= Date: Thu, 10 Dec 2015 15:58:01 -0800 Subject: [PATCH 074/215] 8144654: Improve Marlin logging Reviewed-by: prr, flar --- .../sun/java2d/marlin/ByteArrayCache.java | 4 ++-- .../sun/java2d/marlin/FloatArrayCache.java | 4 ++-- .../sun/java2d/marlin/IntArrayCache.java | 4 ++-- .../sun/java2d/marlin/MarlinConst.java | 9 ++++---- .../sun/java2d/marlin/MarlinProperties.java | 4 ++++ .../sun/java2d/marlin/MarlinUtils.java | 22 ++++--------------- .../sun/java2d/marlin/RendererContext.java | 22 +++++++------------ 7 files changed, 27 insertions(+), 42 deletions(-) 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 cd6ebee89e8..226a3d2e30d 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 @@ -74,7 +74,7 @@ final class ByteArrayCache implements MarlinConst { void putDirtyArray(final byte[] array, final int length) { if (length != arraySize) { if (doChecks) { - System.out.println("ArrayCache: bad length = " + length); + MarlinUtils.logInfo("ArrayCache: bad length = " + length); } return; } @@ -98,7 +98,7 @@ final class ByteArrayCache implements MarlinConst { { if (length != arraySize) { if (doChecks) { - System.out.println("ArrayCache: bad length = " + length); + MarlinUtils.logInfo("ArrayCache: bad length = " + length); } return; } 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 a068ad80fbc..06d7f351e28 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 @@ -75,7 +75,7 @@ final class FloatArrayCache implements MarlinConst { void putDirtyArray(final float[] array, final int length) { if (length != arraySize) { if (doChecks) { - System.out.println("ArrayCache: bad length = " + length); + MarlinUtils.logInfo("ArrayCache: bad length = " + length); } return; } @@ -99,7 +99,7 @@ final class FloatArrayCache implements MarlinConst { { if (length != arraySize) { if (doChecks) { - System.out.println("ArrayCache: bad length = " + length); + MarlinUtils.logInfo("ArrayCache: bad length = " + length); } return; } 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 ccd239cb534..11c5aae84f6 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 @@ -74,7 +74,7 @@ final class IntArrayCache implements MarlinConst { void putDirtyArray(final int[] array, final int length) { if (length != arraySize) { if (doChecks) { - System.out.println("ArrayCache: bad length = " + length); + MarlinUtils.logInfo("ArrayCache: bad length = " + length); } return; } @@ -98,7 +98,7 @@ final class IntArrayCache implements MarlinConst { { if (length != arraySize) { if (doChecks) { - System.out.println("ArrayCache: bad length = " + length); + MarlinUtils.logInfo("ArrayCache: bad length = " + length); } return; } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java index e799504318d..72993ebfd7c 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinConst.java @@ -30,8 +30,8 @@ package sun.java2d.marlin; */ interface MarlinConst { // enable Logs (logger or stdout) - static final boolean enableLogs = false; - // enable Logger + static final boolean enableLogs = MarlinProperties.isLoggingEnabled(); + // use Logger instead of stdout static final boolean useLogger = enableLogs && MarlinProperties.isUseLogger(); // log new RendererContext @@ -47,9 +47,10 @@ interface MarlinConst { static final boolean doStats = enableLogs && MarlinProperties.isDoStats(); // do monitors // disabled to reduce byte-code size a bit... - static final boolean doMonitors = enableLogs && false; // MarlinProperties.isDoMonitors(); + static final boolean doMonitors = false; +// static final boolean doMonitors = enableLogs && MarlinProperties.isDoMonitors(); // do checks - static final boolean doChecks = false; // MarlinProperties.isDoChecks(); + static final boolean doChecks = enableLogs && MarlinProperties.isDoChecks(); // do AA range checks: disable when algorithm / code is stable static final boolean DO_AA_RANGE_CHECK = false; diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java index 002f16d9d5b..bbee15a13fb 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinProperties.java @@ -136,6 +136,10 @@ public final class MarlinProperties { // logging parameters + public static boolean isLoggingEnabled() { + return getBoolean("sun.java2d.renderer.log", "false"); + } + public static boolean isUseLogger() { return getBoolean("sun.java2d.renderer.useLogger", "false"); } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinUtils.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinUtils.java index d218d06f545..aeeacca57bd 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinUtils.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinUtils.java @@ -27,12 +27,12 @@ package sun.java2d.marlin; public final class MarlinUtils { - // TODO: use sun.util.logging.PlatformLogger once in JDK9 - private static final java.util.logging.Logger log; + // Marlin logger + private static final sun.util.logging.PlatformLogger log; static { if (MarlinConst.useLogger) { - log = java.util.logging.Logger.getLogger("sun.java2d.marlin"); + log = sun.util.logging.PlatformLogger.getLogger("sun.java2d.marlin"); } else { log = null; } @@ -53,25 +53,11 @@ public final class MarlinUtils { public static void logException(final String msg, final Throwable th) { if (MarlinConst.useLogger) { -// log.warning(msg, th); - log.log(java.util.logging.Level.WARNING, msg, th); + log.warning(msg, th); } else if (MarlinConst.enableLogs) { System.out.print("WARNING: "); System.out.println(msg); th.printStackTrace(System.err); } } - - // Returns the caller's class and method's name; best effort - // if cannot infer, return the logger's name. - static String getCallerInfo(String className) { - String sourceClassName = null; - String sourceMethodName = null; - - if (sourceClassName != null) { - return sourceClassName + " " + sourceMethodName; - } else { - return "unknown"; - } - } } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java index 7af675b16b7..a767651f5d5 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java @@ -31,7 +31,6 @@ import java.lang.ref.WeakReference; import java.util.concurrent.atomic.AtomicInteger; import static sun.java2d.marlin.ArrayCache.*; import sun.java2d.marlin.MarlinRenderingEngine.NormalizingPathIterator; -import static sun.java2d.marlin.MarlinUtils.getCallerInfo; import static sun.java2d.marlin.MarlinUtils.logInfo; /** @@ -39,7 +38,6 @@ import static sun.java2d.marlin.MarlinUtils.logInfo; */ final class RendererContext implements MarlinConst { - private static final String className = RendererContext.class.getName(); // RendererContext creation counter private static final AtomicInteger contextCount = new AtomicInteger(1); // RendererContext statistics @@ -214,8 +212,7 @@ final class RendererContext implements MarlinConst { } if (doLogOverSize) { - logInfo("getDirtyByteArray[oversize]: length=\t" + length - + "\tfrom=\t" + getCallerInfo(className)); + logInfo("getDirtyByteArray[oversize]: length=\t" + length); } return new byte[length]; @@ -254,7 +251,7 @@ final class RendererContext implements MarlinConst { if (doLogWidenArray) { logInfo("widenDirtyByteArray[" + res.length + "]: usedSize=\t" + usedSize + "\tlength=\t" + length + "\tneeded length=\t" - + needSize + "\tfrom=\t" + getCallerInfo(className)); + + needSize); } return res; } @@ -275,8 +272,7 @@ final class RendererContext implements MarlinConst { } if (doLogOverSize) { - logInfo("getIntArray[oversize]: length=\t" + length + "\tfrom=\t" - + getCallerInfo(className)); + logInfo("getIntArray[oversize]: length=\t" + length); } return new int[length]; @@ -306,7 +302,7 @@ final class RendererContext implements MarlinConst { if (doLogWidenArray) { logInfo("widenIntArray[" + res.length + "]: usedSize=\t" + usedSize + "\tlength=\t" + length + "\tneeded length=\t" - + needSize + "\tfrom=\t" + getCallerInfo(className)); + + needSize); } return res; } @@ -338,8 +334,7 @@ final class RendererContext implements MarlinConst { } if (doLogOverSize) { - logInfo("getDirtyIntArray[oversize]: length=\t" + length - + "\tfrom=\t" + getCallerInfo(className)); + logInfo("getDirtyIntArray[oversize]: length=\t" + length); } return new int[length]; @@ -369,7 +364,7 @@ final class RendererContext implements MarlinConst { if (doLogWidenArray) { logInfo("widenDirtyIntArray[" + res.length + "]: usedSize=\t" + usedSize + "\tlength=\t" + length + "\tneeded length=\t" - + needSize + "\tfrom=\t" + getCallerInfo(className)); + + needSize); } return res; } @@ -399,8 +394,7 @@ final class RendererContext implements MarlinConst { } if (doLogOverSize) { - logInfo("getDirtyFloatArray[oversize]: length=\t" + length - + "\tfrom=\t" + getCallerInfo(className)); + logInfo("getDirtyFloatArray[oversize]: length=\t" + length); } return new float[length]; @@ -430,7 +424,7 @@ final class RendererContext implements MarlinConst { if (doLogWidenArray) { logInfo("widenDirtyFloatArray[" + res.length + "]: usedSize=\t" + usedSize + "\tlength=\t" + length + "\tneeded length=\t" - + needSize + "\tfrom=\t" + getCallerInfo(className)); + + needSize); } return res; } From b831ed3c8b030fb26855b4df9046ba3a1b9ddfa3 Mon Sep 17 00:00:00 2001 From: Naveen Kumar Date: Tue, 15 Dec 2015 16:42:30 +0900 Subject: [PATCH 075/215] 8139572: SimpleDateFormat parse month stand-alone format bug Reviewed-by: okutsu --- .../classes/java/text/SimpleDateFormat.java | 15 +++ .../text/Format/DateFormat/Bug8139572.java | 120 ++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 jdk/test/java/text/Format/DateFormat/Bug8139572.java diff --git a/jdk/src/java.base/share/classes/java/text/SimpleDateFormat.java b/jdk/src/java.base/share/classes/java/text/SimpleDateFormat.java index 488e43635b6..bced263c072 100644 --- a/jdk/src/java.base/share/classes/java/text/SimpleDateFormat.java +++ b/jdk/src/java.base/share/classes/java/text/SimpleDateFormat.java @@ -1856,6 +1856,7 @@ public class SimpleDateFormat extends DateFormat { if (patternCharIndex == PATTERN_HOUR_OF_DAY1 || patternCharIndex == PATTERN_HOUR1 || (patternCharIndex == PATTERN_MONTH && count <= 2) || + (patternCharIndex == PATTERN_MONTH_STANDALONE && count <= 2) || patternCharIndex == PATTERN_YEAR || patternCharIndex == PATTERN_WEEK_YEAR) { // It would be good to unify this with the obeyCount logic below, @@ -1976,6 +1977,20 @@ public class SimpleDateFormat extends DateFormat { } break parsing; + case PATTERN_MONTH_STANDALONE: // 'L' + if (count <= 2) { + // Don't want to parse the month if it is a string + // while pattern uses numeric style: L or LL + //[we computed 'value' above.] + calb.set(Calendar.MONTH, value - 1); + return pos.index; + } + Map maps = getDisplayNamesMap(field, locale); + if ((index = matchString(text, start, field, maps, calb)) > 0) { + return index; + } + break parsing; + case PATTERN_HOUR_OF_DAY1: // 'k' 1-based. eg, 23:59 + 1 hour =>> 24:59 if (!isLenient()) { // Validate the hour value in non-lenient diff --git a/jdk/test/java/text/Format/DateFormat/Bug8139572.java b/jdk/test/java/text/Format/DateFormat/Bug8139572.java new file mode 100644 index 00000000000..d55196b3a23 --- /dev/null +++ b/jdk/test/java/text/Format/DateFormat/Bug8139572.java @@ -0,0 +1,120 @@ +/* + * 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 8139572 + * @summary SimpleDateFormat parse month stand-alone format bug + * @compile -encoding utf-8 Bug8139572.java + * @run main Bug8139572 + */ +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; + +public class Bug8139572 { + + private static final Locale RUSSIAN = new Locale("ru"); + private static final Date SEPT12 = new GregorianCalendar(2015, Calendar.SEPTEMBER, 12).getTime(); + + private static final String[] PATTERNS = { + "L", + "dd L", + "dd L yy", + "dd L yyyy", + "LL", + "dd LL", + "dd LL yy", + "dd LL yyyy", + "LLL", + "dd LLL", + "dd LLL yy", + "dd LLL yyyy", + "LLLL", + "dd LLLL", + "dd LLLL yy", + "dd LLLL yyyy" + }; + + private static final String[] APPLIED = { + "9", + "12 09", + "12 09 15", + "12 09 2015", + "09", + "12 09", + "12 09 15", + "12 09 2015", + "сентября", + "12 сентября", + "12 сентября 15", + "12 сентября 2015", + "сентября", + "12 сентября", + "12 сентября 15", + "12 сентября 2015" + }; + + private static final String[] EXPECTED = { + "9", + "12 9", + "12 9 15", + "12 9 2015", + "09", + "12 09", + "12 09 15", + "12 09 2015", + "сент.", + "12 сент.", + "12 сент. 15", + "12 сент. 2015", + "сентябрь", + "12 сентябрь", + "12 сентябрь 15", + "12 сентябрь 2015" + }; + + public static void main(String[] args) throws ParseException { + + for (int i = 0; i < PATTERNS.length; i++) { + SimpleDateFormat fmt = new SimpleDateFormat(PATTERNS[i], RUSSIAN); + Date standAloneDate = fmt.parse(APPLIED[i]); + String str = fmt.format(standAloneDate); + if (!EXPECTED[i].equals(str)) { + throw new RuntimeException("bad result: got '" + str + "', expected '" + EXPECTED[i] + "'"); + } + } + + SimpleDateFormat fmt = new SimpleDateFormat("", RUSSIAN); + for (int j = 0; j < PATTERNS.length; j++) { + fmt.applyPattern(PATTERNS[j]); + String str = fmt.format(SEPT12); + if (!EXPECTED[j].equals(str)) { + throw new RuntimeException("bad result: got '" + str + "', expected '" + EXPECTED[j] + "'"); + } + } + } +} From 61f49a066360e0fef0d674d753b0e8ecd9e009e6 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Tue, 15 Dec 2015 10:11:04 +0000 Subject: [PATCH 076/215] 8145390: Remove sun.misc.Queue and replace usages with standard Collections Reviewed-by: psandoz, mchung, serb --- .../share/classes/sun/misc/Queue.java | 214 ------------------ .../share/classes/sun/applet/AppletPanel.java | 14 +- 2 files changed, 6 insertions(+), 222 deletions(-) delete mode 100644 jdk/src/java.base/share/classes/sun/misc/Queue.java diff --git a/jdk/src/java.base/share/classes/sun/misc/Queue.java b/jdk/src/java.base/share/classes/sun/misc/Queue.java deleted file mode 100644 index 0eed6a08779..00000000000 --- a/jdk/src/java.base/share/classes/sun/misc/Queue.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 1996, 2011, 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.misc; - -import java.util.Enumeration; -import java.util.NoSuchElementException; - -/** - * Queue: implements a simple queue mechanism. Allows for enumeration of the - * elements. - * - * @author Herb Jellinek - */ - -public class Queue { - - int length = 0; - - QueueElement head = null; - QueueElement tail = null; - - public Queue() { - } - - /** - * Enqueue an object. - */ - public synchronized void enqueue(T obj) { - - QueueElement newElt = new QueueElement<>(obj); - - if (head == null) { - head = newElt; - tail = newElt; - length = 1; - } else { - newElt.next = head; - head.prev = newElt; - head = newElt; - length++; - } - notify(); - } - - /** - * Dequeue the oldest object on the queue. Will wait indefinitely. - * - * @return the oldest object on the queue. - * @exception java.lang.InterruptedException if any thread has - * interrupted this thread. - */ - public T dequeue() throws InterruptedException { - return dequeue(0L); - } - - /** - * Dequeue the oldest object on the queue. - * @param timeOut the number of milliseconds to wait for something - * to arrive. - * - * @return the oldest object on the queue. - * @exception java.lang.InterruptedException if any thread has - * interrupted this thread. - */ - public synchronized T dequeue(long timeOut) - throws InterruptedException { - - while (tail == null) { - wait(timeOut); - } - QueueElement elt = tail; - tail = elt.prev; - if (tail == null) { - head = null; - } else { - tail.next = null; - } - length--; - return elt.obj; - } - - /** - * Is the queue empty? - * @return true if the queue is empty. - */ - public synchronized boolean isEmpty() { - return (tail == null); - } - - /** - * Returns an enumeration of the elements in Last-In, First-Out - * order. Use the Enumeration methods on the returned object to - * fetch the elements sequentially. - */ - public final synchronized Enumeration elements() { - return new LIFOQueueEnumerator<>(this); - } - - /** - * Returns an enumeration of the elements in First-In, First-Out - * order. Use the Enumeration methods on the returned object to - * fetch the elements sequentially. - */ - public final synchronized Enumeration reverseElements() { - return new FIFOQueueEnumerator<>(this); - } - - public synchronized void dump(String msg) { - System.err.println(">> "+msg); - System.err.println("["+length+" elt(s); head = "+ - (head == null ? "null" : (head.obj)+"")+ - " tail = "+(tail == null ? "null" : (tail.obj)+"")); - QueueElement cursor = head; - QueueElement last = null; - while (cursor != null) { - System.err.println(" "+cursor); - last = cursor; - cursor = cursor.next; - } - if (last != tail) { - System.err.println(" tail != last: "+tail+", "+last); - } - System.err.println("]"); - } -} - -final class FIFOQueueEnumerator implements Enumeration { - Queue queue; - QueueElement cursor; - - FIFOQueueEnumerator(Queue q) { - queue = q; - cursor = q.tail; - } - - public boolean hasMoreElements() { - return (cursor != null); - } - - public T nextElement() { - synchronized (queue) { - if (cursor != null) { - QueueElement result = cursor; - cursor = cursor.prev; - return result.obj; - } - } - throw new NoSuchElementException("FIFOQueueEnumerator"); - } -} - -final class LIFOQueueEnumerator implements Enumeration { - Queue queue; - QueueElement cursor; - - LIFOQueueEnumerator(Queue q) { - queue = q; - cursor = q.head; - } - - public boolean hasMoreElements() { - return (cursor != null); - } - - public T nextElement() { - synchronized (queue) { - if (cursor != null) { - QueueElement result = cursor; - cursor = cursor.next; - return result.obj; - } - } - throw new NoSuchElementException("LIFOQueueEnumerator"); - } -} - -class QueueElement { - QueueElement next = null; - QueueElement prev = null; - - T obj = null; - - QueueElement(T obj) { - this.obj = obj; - } - - public String toString() { - return "QueueElement[obj="+obj+(prev == null ? " null" : " prev")+ - (next == null ? " null" : " next")+"]"; - } -} diff --git a/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java b/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java index fcefccd9893..a9bacd5c3f2 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletPanel.java @@ -38,6 +38,7 @@ import java.net.URL; import java.security.*; import java.util.*; import java.util.Locale; +import java.util.concurrent.LinkedBlockingQueue; import sun.awt.AWTAccessor; import sun.awt.AppContext; import sun.awt.EmbeddedFrame; @@ -45,7 +46,6 @@ import sun.awt.SunToolkit; import sun.misc.ManagedLocalsThread; import sun.misc.MessageUtils; import sun.misc.PerformanceLogger; -import sun.misc.Queue; import sun.security.util.SecurityConstants; /** @@ -247,8 +247,7 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { /** * AppletEvent Queue */ - private Queue queue = null; - + private LinkedBlockingQueue queue = null; public synchronized void addAppletListener(AppletListener l) { listeners = AppletEventMulticaster.add(listeners, l); @@ -276,10 +275,9 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { synchronized(this) { if (queue == null) { //System.out.println("SEND0= " + id); - queue = new Queue<>(); + queue = new LinkedBlockingQueue<>(); } - Integer eventId = Integer.valueOf(id); - queue.enqueue(eventId); + boolean inserted = queue.add(id); notifyAll(); } if (id == APPLET_QUIT) { @@ -303,8 +301,8 @@ abstract class AppletPanel extends Panel implements AppletStub, Runnable { while (queue == null || queue.isEmpty()) { wait(); } - Integer eventId = queue.dequeue(); - return new AppletEvent(this, eventId.intValue(), null); + int eventId = queue.take(); + return new AppletEvent(this, eventId, null); } boolean emptyEventQueue() { From 5b80991feaf1f0c2ea8ec799076d88610566fa8e Mon Sep 17 00:00:00 2001 From: Sergei Kovalev Date: Fri, 11 Dec 2015 16:35:59 +0300 Subject: [PATCH 077/215] 8078423: [TESTBUG] javax/print/PrintSEUmlauts/PrintSEUmlauts.java relies on system locale Reviewed-by: martin --- jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java b/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java index f87549747b2..962ef5e8bc0 100644 --- a/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java +++ b/jdk/test/javax/print/PrintSEUmlauts/PrintSEUmlauts.java @@ -107,14 +107,14 @@ public class PrintSEUmlauts implements Printable { System.err.println("printing content"); System.err.println(content); } - throw new RuntimeException("Expected to represent 'ä' but not found!"); + throw new RuntimeException("Expected to represent '\u00e4' but not found!"); } System.err.println("SUCCESS"); } public int print(Graphics g, PageFormat pf, int pg) { if (pg > 0) return NO_SUCH_PAGE; - g.drawString("ä", 100, 100); + g.drawString("\u00e4", 100, 100); return PAGE_EXISTS; } } From ec26043caf3ca01d93a6dfaa1ac1a30e50149768 Mon Sep 17 00:00:00 2001 From: Shinya Yoshida Date: Fri, 11 Dec 2015 11:20:10 -0800 Subject: [PATCH 078/215] 8144903: JShell: determine incorrectly the type of the expression which is array type of captured type Fix and clean-up the processing of types (esp. captured types) into type names for use in generated temp vars Reviewed-by: mcimadamore, jlahoda, rfield --- .../share/classes/jdk/jshell/TypePrinter.java | 35 ++++++++++++++----- langtools/test/jdk/jshell/TypeNameTest.java | 27 ++++++++------ langtools/test/jdk/jshell/VariablesTest.java | 11 ++++++ 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java index 2ac9530f0a6..e35fe5e7d7b 100644 --- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java @@ -41,15 +41,15 @@ import java.util.function.BinaryOperator; * Print types in source form. */ class TypePrinter extends Printer { + private static final String OBJECT = "Object"; private final JavacMessages messages; private final BinaryOperator fullClassNameAndPackageToClass; - private final Type typeToPrint; + private boolean useWildCard = false; TypePrinter(JavacMessages messages, BinaryOperator fullClassNameAndPackageToClass, Type typeToPrint) { this.messages = messages; this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass; - this.typeToPrint = typeToPrint; } @Override @@ -64,21 +64,40 @@ class TypePrinter extends Printer { @Override public String visitCapturedType(Type.CapturedType t, Locale locale) { - if (t == typeToPrint) { - return visit(t.getUpperBound(), locale); - } else { - return visit(t.wildcard, locale); + return visit(t.wildcard, locale); + } + + @Override + public String visitWildcardType(Type.WildcardType wt, Locale locale) { + if (useWildCard) { // at TypeArgument(ex: List) + return super.visitWildcardType(wt, locale); + } else { // at TopLevelType(ex: ? extends List, ? extends Number[][]) + Type extendsBound = wt.getExtendsBound(); + return extendsBound == null + ? OBJECT + : visit(extendsBound, locale); } } @Override public String visitType(Type t, Locale locale) { String s = (t.tsym == null || t.tsym.name == null) - ? "Object" // none + ? OBJECT // none : t.tsym.name.toString(); return s; } + @Override + public String visitClassType(ClassType ct, Locale locale) { + boolean prevUseWildCard = useWildCard; + try { + useWildCard = true; + return super.visitClassType(ct, locale); + } finally { + useWildCard = prevUseWildCard; + } + } + /** * Converts a class name into a (possibly localized) string. Anonymous * inner classes get converted into a localized string. @@ -101,7 +120,7 @@ class TypePrinter extends Printer { } return s.toString(); ***/ - return "Object"; + return OBJECT; } else if (sym.name.length() == 0) { // Anonymous String s; diff --git a/langtools/test/jdk/jshell/TypeNameTest.java b/langtools/test/jdk/jshell/TypeNameTest.java index 41dbe7004cb..4f1b9cef418 100644 --- a/langtools/test/jdk/jshell/TypeNameTest.java +++ b/langtools/test/jdk/jshell/TypeNameTest.java @@ -23,7 +23,8 @@ /* * @test - * @summary null test + * @bug 8144903 + * @summary Tests for determining the type from the expression * @build KullaTesting TestingInputStream * @run testng TypeNameTest */ @@ -34,7 +35,6 @@ import org.testng.annotations.Test; import static jdk.jshell.Snippet.Status.VALID; import static org.testng.Assert.assertEquals; -import static jdk.jshell.Snippet.Status.OVERWRITTEN; @Test public class TypeNameTest extends KullaTesting { @@ -62,6 +62,11 @@ public class TypeNameTest extends KullaTesting { assertEquals(sn.typeName(), "Class"); } + public void testArrayTypeOfCapturedTypeName() { + VarSnippet sn = (VarSnippet) varKey(assertEval("\"\".getClass().getEnumConstants();")); + assertEquals(sn.typeName(), "String[]"); + } + public void testJavaLang() { VarSnippet sn = (VarSnippet) varKey(assertEval("\"\";")); assertEquals(sn.typeName(), "String"); @@ -83,14 +88,16 @@ public class TypeNameTest extends KullaTesting { VarSnippet sn3 = (VarSnippet) varKey(assertEval("list3.iterator().next()")); assertEquals(sn3.typeName(), "Object"); assertEval("class Test1 { public X get() { return null; } }"); - Snippet x = varKey(assertEval("Test1 x = new Test1<>();")); - VarSnippet sn4 = (VarSnippet) varKey(assertEval("x.get()")); - assertEquals(sn4.typeName(), "CharSequence"); - assertEval("class Foo { public X get() { return null; } }"); - assertEval("Foo x = new Foo<>();", - ste(MAIN_SNIPPET, VALID, VALID, true, null), - ste(x, VALID, OVERWRITTEN, false, MAIN_SNIPPET)); - VarSnippet sn5 = (VarSnippet) varKey(assertEval("x.get()")); + Snippet x = varKey(assertEval("Test1 test1 = new Test1<>();")); + VarSnippet sn4 = (VarSnippet) varKey(assertEval("test1.get()")); + assertEquals(sn4.typeName(), "Object"); + assertEval("class Test2 { public X get() { return null; } }"); + assertEval("Test2 test2 = new Test2<>();"); + VarSnippet sn5 = (VarSnippet) varKey(assertEval("test2.get()")); assertEquals(sn5.typeName(), "Object"); + assertEval("class Test3 { T[][] get() { return null; } }", added(VALID)); + assertEval("Test3 test3 = new Test3<>();"); + VarSnippet sn6 = (VarSnippet) varKey(assertEval("test3.get()")); + assertEquals(sn6.typeName(), "String[][]"); } } diff --git a/langtools/test/jdk/jshell/VariablesTest.java b/langtools/test/jdk/jshell/VariablesTest.java index 73a25a372c1..3a374a0b52c 100644 --- a/langtools/test/jdk/jshell/VariablesTest.java +++ b/langtools/test/jdk/jshell/VariablesTest.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8144903 * @summary Tests for EvaluationState.variables * @build KullaTesting TestingInputStream ExpectedDiagnostic * @run testng VariablesTest @@ -184,6 +185,16 @@ public class VariablesTest extends KullaTesting { assertActiveKeys(); } + public void variablesTemporaryArrayOfCapturedType() { + assertEval("class Test { T[][] get() { return null; } }", added(VALID)); + assertEval("Test test() { return new Test<>(); }", added(VALID)); + assertEval("test().get()", added(VALID)); + assertVariables(variable("String[][]", "$1")); + assertEval("\"\".getClass().getEnumConstants()", added(VALID)); + assertVariables(variable("String[][]", "$1"), variable("String[]", "$2")); + assertActiveKeys(); + } + public void variablesClassReplace() { assertEval("import java.util.*;", added(VALID)); Snippet var = varKey(assertEval("List list = new ArrayList<>();", "[]", From 5b1765f25dc24d89046d2acf08859b68301d145e Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 11 Dec 2015 11:38:18 -0800 Subject: [PATCH 079/215] 8144245: [PIT] javax/imageio/plugins/shared/WriteAfterAbort.java Reset stream position after abort; change IAEs to NPEs. Reviewed-by: prr, serb --- .../com/sun/imageio/plugins/tiff/TIFFIFD.java | 9 +- .../imageio/plugins/tiff/TIFFImageWriter.java | 56 ++- jdk/test/ProblemList.txt | 2 - .../plugins/shared/WriteAfterAbort.java | 16 +- .../tiff/WriteToSequenceAfterAbort.java | 376 ++++++++++++++++++ 5 files changed, 449 insertions(+), 10 deletions(-) create mode 100644 jdk/test/javax/imageio/plugins/tiff/WriteToSequenceAfterAbort.java 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 6803f634762..7c14f8daf85 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 @@ -472,6 +472,13 @@ public class TIFFIFD extends TIFFDirectory { // Read tag number, value type, and value count. int tagNumber = stream.readUnsignedShort(); int type = stream.readUnsignedShort(); + int sizeOfType; + try { + sizeOfType = TIFFTag.getSizeOfType(type); + } catch (IllegalArgumentException e) { + throw new IIOException("Illegal type " + type + + " for tag number " + tagNumber, e); + } int count = (int)stream.readUnsignedInt(); // Get the associated TIFFTag. @@ -510,7 +517,7 @@ public class TIFFIFD extends TIFFDirectory { } } - int size = count*TIFFTag.getSizeOfType(type); + int size = count*sizeOfType; if (size > 4 || tag.isIFDPointer()) { // The IFD entry value is a pointer to the actual field value. long offset = stream.readUnsignedInt(); 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 08c1f0ecb9a..6a90e0677c9 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 @@ -205,6 +205,10 @@ public class TIFFImageWriter extends ImageWriter { // Next available space. private long nextSpace = 0L; + private long prevStreamPosition; + private long prevHeaderPosition; + private long prevNextSpace; + // Whether a sequence is being written. private boolean isWritingSequence = false; private boolean isInsertingEmpty = false; @@ -2300,7 +2304,14 @@ public class TIFFImageWriter extends ImageWriter { public void write(IIOMetadata sm, IIOImage iioimage, ImageWriteParam p) throws IOException { + if (stream == null) { + throw new IllegalStateException("output == null!"); + } + markPositions(); write(sm, iioimage, p, true, true); + if (abortRequested()) { + resetPositions(); + } } private void writeHeader() throws IOException { @@ -2333,7 +2344,7 @@ public class TIFFImageWriter extends ImageWriter { throw new IllegalStateException("output == null!"); } if (iioimage == null) { - throw new NullPointerException("image == null!"); + throw new IllegalArgumentException("image == null!"); } if(iioimage.hasRaster() && !canWriteRasters()) { throw new UnsupportedOperationException @@ -2767,7 +2778,7 @@ public class TIFFImageWriter extends ImageWriter { throw new IllegalStateException("Output not set!"); } if (image == null) { - throw new NullPointerException("image == null!"); + throw new IllegalArgumentException("image == null!"); } // Locate the position of the old IFD (ifd) and the location @@ -2779,9 +2790,16 @@ public class TIFFImageWriter extends ImageWriter { // imageIndex is < -1 or is too big thereby satisfying the spec. locateIFD(imageIndex, ifdpos, ifd); + markPositions(); + // Seek to the position containing the pointer to the old IFD. stream.seek(ifdpos[0]); + // Save the previous pointer value in case of abort. + stream.mark(); + long prevPointerValue = stream.readUnsignedInt(); + stream.reset(); + // Update next space pointer in anticipation of next write. if(ifdpos[0] + 4 > nextSpace) { nextSpace = ifdpos[0] + 4; @@ -2805,6 +2823,12 @@ public class TIFFImageWriter extends ImageWriter { // Update the new IFD to point to the old IFD. stream.writeInt((int)ifd[0]); // Don't need to update nextSpace here as already done in write(). + + if (abortRequested()) { + stream.seek(ifdpos[0]); + stream.writeInt((int)prevPointerValue); + resetPositions(); + } } // ----- BEGIN insert/writeEmpty methods ----- @@ -2834,7 +2858,7 @@ public class TIFFImageWriter extends ImageWriter { } if(imageType == null) { - throw new NullPointerException("imageType == null!"); + throw new IllegalArgumentException("imageType == null!"); } if(width < 1 || height < 1) { @@ -2891,6 +2915,10 @@ public class TIFFImageWriter extends ImageWriter { IIOMetadata imageMetadata, List thumbnails, ImageWriteParam param) throws IOException { + if (stream == null) { + throw new IllegalStateException("output == null!"); + } + checkParamsEmpty(imageType, width, height, thumbnails); this.isWritingEmpty = true; @@ -2901,8 +2929,12 @@ public class TIFFImageWriter extends ImageWriter { 0, 0, emptySM.getWidth(), emptySM.getHeight(), emptySM, imageType.getColorModel()); + markPositions(); write(streamMetadata, new IIOImage(emptyImage, null, imageMetadata), param, true, false); + if (abortRequested()) { + resetPositions(); + } } public void endInsertEmpty() throws IOException { @@ -3015,7 +3047,7 @@ public class TIFFImageWriter extends ImageWriter { throw new IllegalStateException("Output not set!"); } if (region == null) { - throw new NullPointerException("region == null!"); + throw new IllegalArgumentException("region == null!"); } if (region.getWidth() < 1) { throw new IllegalArgumentException("region.getWidth() < 1!"); @@ -3200,7 +3232,7 @@ public class TIFFImageWriter extends ImageWriter { } if (image == null) { - throw new NullPointerException("image == null!"); + throw new IllegalArgumentException("image == null!"); } if (!inReplacePixelsNest) { @@ -3559,6 +3591,20 @@ public class TIFFImageWriter extends ImageWriter { // ----- END replacePixels methods ----- + // Save stream positions for use when aborted. + private void markPositions() throws IOException { + prevStreamPosition = stream.getStreamPosition(); + prevHeaderPosition = headerPosition; + prevNextSpace = nextSpace; + } + + // Reset to positions saved by markPositions(). + private void resetPositions() throws IOException { + stream.seek(prevStreamPosition); + headerPosition = prevHeaderPosition; + nextSpace = prevNextSpace; + } + public void reset() { super.reset(); diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 51abaacbf53..2a18c6adef2 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -310,8 +310,6 @@ javax/sound/midi/Gervill/SoftProvider/GetDevice.java generic-all # jdk_imageio -javax/imageio/plugins/shared/WriteAfterAbort.java generic-all - ############################################################################ # jdk_swing diff --git a/jdk/test/javax/imageio/plugins/shared/WriteAfterAbort.java b/jdk/test/javax/imageio/plugins/shared/WriteAfterAbort.java index 4b503d2fe6f..f1be068cdfe 100644 --- a/jdk/test/javax/imageio/plugins/shared/WriteAfterAbort.java +++ b/jdk/test/javax/imageio/plugins/shared/WriteAfterAbort.java @@ -130,13 +130,25 @@ public final class WriteAfterAbort implements IIOWriteProgressListener { ImageWriterSpi.class, provider -> true, true); // Validates all supported ImageWriters + int numFailures = 0; while (iter.hasNext()) { final WriteAfterAbort writeAfterAbort = new WriteAfterAbort(); final ImageWriter writer = iter.next().createWriterInstance(); System.out.println("ImageWriter = " + writer); - writeAfterAbort.test(writer); + try { + writeAfterAbort.test(writer); + } catch (Exception e) { + System.err.println("Test failed for \"" + + writer.getOriginatingProvider().getFormatNames()[0] + + "\" format."); + numFailures++; + } + } + if (numFailures == 0) { + System.out.println("Test passed."); + } else { + throw new RuntimeException("Test failed."); } - System.out.println("Test passed"); } // Callbacks diff --git a/jdk/test/javax/imageio/plugins/tiff/WriteToSequenceAfterAbort.java b/jdk/test/javax/imageio/plugins/tiff/WriteToSequenceAfterAbort.java new file mode 100644 index 00000000000..55461f36f24 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/tiff/WriteToSequenceAfterAbort.java @@ -0,0 +1,376 @@ +/* + * 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. + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.imageio.ImageWriter; +import javax.imageio.event.IIOWriteProgressListener; +import javax.imageio.stream.ImageOutputStream; + +import static java.awt.image.BufferedImage.TYPE_BYTE_BINARY; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.util.Vector; +import javax.imageio.IIOImage; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; + +/** + * @test + * @bug 8144245 + * @summary Ensure aborting write works properly for a TIFF sequence. + */ +public final class WriteToSequenceAfterAbort implements IIOWriteProgressListener { + + private volatile boolean abortFlag = true; + private volatile boolean isAbortCalled; + private volatile boolean isCompleteCalled; + private volatile boolean isProgressCalled; + private volatile boolean isStartedCalled; + private static final int WIDTH = 100; + private static final int HEIGHT = 100; + private static final int NUM_TILES_XY = 3; + + private class TiledImage implements RenderedImage { + private final BufferedImage tile; + private final BufferedImage image; + private final int numXTiles, numYTiles; + private boolean isImageInitialized = false; + + TiledImage(BufferedImage tile, int numXTiles, int numYTiles) { + this.tile = tile; + this.numXTiles = numXTiles; + this.numYTiles = numYTiles; + image = new BufferedImage(getWidth(), getHeight(), tile.getType()); + } + + @Override + public Vector getSources() { + return null; + } + + @Override + public Object getProperty(String string) { + return java.awt.Image.UndefinedProperty; + } + + @Override + public String[] getPropertyNames() { + return new String[0]; + } + + @Override + public ColorModel getColorModel() { + return tile.getColorModel(); + } + + @Override + public SampleModel getSampleModel() { + return tile.getSampleModel(); + } + + @Override + public int getWidth() { + return numXTiles*tile.getWidth(); + } + + @Override + public int getHeight() { + return numYTiles*tile.getHeight(); + } + + @Override + public int getMinX() { + return 0; + } + + @Override + public int getMinY() { + return 0; + } + + @Override + public int getNumXTiles() { + return numXTiles; + } + + @Override + public int getNumYTiles() { + return numYTiles; + } + + @Override + public int getMinTileX() { + return 0; + } + + @Override + public int getMinTileY() { + return 0; + } + + @Override + public int getTileWidth() { + return tile.getWidth(); + } + + @Override + public int getTileHeight() { + return tile.getHeight(); + } + + @Override + public int getTileGridXOffset() { + return 0; + } + + @Override + public int getTileGridYOffset() { + return 0; + } + + @Override + public Raster getTile(int x, int y) { + WritableRaster r = tile.getRaster(); + return r.createWritableTranslatedChild(x*tile.getWidth(), + y*tile.getHeight()); + } + + @Override + public Raster getData() { + return getAsBufferedImage().getData(); + } + + @Override + public Raster getData(Rectangle r) { + return getAsBufferedImage().getData(r); + } + + @Override + public WritableRaster copyData(WritableRaster wr) { + return getAsBufferedImage().copyData(wr); + } + + public BufferedImage getAsBufferedImage() { + synchronized (image) { + if (!isImageInitialized) { + int tx0 = getMinTileX(), ty0 = getMinTileY(); + int txN = tx0 + getNumXTiles(), tyN = ty0 + getNumYTiles(); + for (int j = ty0; j < tyN; j++) { + for (int i = tx0; i < txN; i++) { + image.setData(getTile(i, j)); + } + } + } + isImageInitialized = true; + } + return image; + } + } + + private void test(final ImageWriter writer) throws IOException { + String suffix = writer.getOriginatingProvider().getFileSuffixes()[0]; + + // Image initialization + BufferedImage imageUpperLeft = + new BufferedImage(WIDTH, HEIGHT, TYPE_BYTE_BINARY); + Graphics2D g = imageUpperLeft.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, WIDTH/2, HEIGHT/2); + g.dispose(); + BufferedImage imageLowerRight = + new BufferedImage(WIDTH, HEIGHT, TYPE_BYTE_BINARY); + g = imageLowerRight.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(WIDTH/2, HEIGHT/2, WIDTH/2, HEIGHT/2); + g.dispose(); + TiledImage[] images = new TiledImage[] { + new TiledImage(imageUpperLeft, NUM_TILES_XY, NUM_TILES_XY), + new TiledImage(imageUpperLeft, NUM_TILES_XY, NUM_TILES_XY), + new TiledImage(imageLowerRight, NUM_TILES_XY, NUM_TILES_XY), + new TiledImage(imageLowerRight, NUM_TILES_XY, NUM_TILES_XY) + }; + + // File initialization + File file = File.createTempFile("temp", "." + suffix); + file.deleteOnExit(); + FileOutputStream fos = new SkipWriteOnAbortOutputStream(file); + ImageOutputStream ios = ImageIO.createImageOutputStream(fos); + writer.setOutput(ios); + writer.addIIOWriteProgressListener(this); + + writer.prepareWriteSequence(null); + boolean[] abortions = new boolean[] {true, false, true, false}; + for (int i = 0; i < 4; i++) { + abortFlag = abortions[i]; + isAbortCalled = false; + isCompleteCalled = false; + isProgressCalled = false; + isStartedCalled = false; + + TiledImage image = images[i]; + if (abortFlag) { + // This write will be aborted, and file will not be touched + writer.writeToSequence(new IIOImage(image, null, null), null); + if (!isStartedCalled) { + throw new RuntimeException("Started should be called"); + } + if (!isProgressCalled) { + throw new RuntimeException("Progress should be called"); + } + if (!isAbortCalled) { + throw new RuntimeException("Abort should be called"); + } + if (isCompleteCalled) { + throw new RuntimeException("Complete should not be called"); + } + } else { + // This write should be completed successfully and the file should + // contain correct image data. + writer.writeToSequence(new IIOImage(image, null, null), null); + if (!isStartedCalled) { + throw new RuntimeException("Started should be called"); + } + if (!isProgressCalled) { + throw new RuntimeException("Progress should be called"); + } + if (isAbortCalled) { + throw new RuntimeException("Abort should not be called"); + } + if (!isCompleteCalled) { + throw new RuntimeException("Complete should be called"); + } + } + } + + writer.endWriteSequence(); + writer.dispose(); + ios.close(); + + // Validates content of the file. + ImageReader reader = ImageIO.getImageReader(writer); + ImageInputStream iis = ImageIO.createImageInputStream(file); + reader.setInput(iis); + for (int i = 0; i < 2; i++) { + System.out.println("Testing image " + i); + BufferedImage imageRead = reader.read(i); + BufferedImage imageWrite = images[2 * i].getAsBufferedImage(); + for (int x = 0; x < WIDTH; ++x) { + for (int y = 0; y < HEIGHT; ++y) { + if (imageRead.getRGB(x, y) != imageWrite.getRGB(x, y)) { + throw new RuntimeException("Test failed for image " + i); + } + } + } + } + } + + public static void main(final String[] args) throws IOException { + WriteToSequenceAfterAbort writeAfterAbort = new WriteToSequenceAfterAbort(); + ImageWriter writer = ImageIO.getImageWritersByFormatName("TIFF").next(); + writeAfterAbort.test(writer); + System.out.println("Test passed."); + } + + // Callbacks + + @Override + public void imageComplete(ImageWriter source) { + isCompleteCalled = true; + } + + @Override + public void imageProgress(ImageWriter source, float percentageDone) { + isProgressCalled = true; + if (percentageDone > 50 && abortFlag) { + source.abort(); + } + } + + @Override + public void imageStarted(ImageWriter source, int imageIndex) { + isStartedCalled = true; + } + + @Override + public void writeAborted(final ImageWriter source) { + isAbortCalled = true; + } + + @Override + public void thumbnailComplete(ImageWriter source) { + } + + @Override + public void thumbnailProgress(ImageWriter source, float percentageDone) { + } + + @Override + public void thumbnailStarted(ImageWriter source, int imageIndex, + int thumbnailIndex) { + } + + /** + * We need to skip writes on abort, because content of the file after abort + * is undefined. + */ + private class SkipWriteOnAbortOutputStream extends FileOutputStream { + + SkipWriteOnAbortOutputStream(File file) throws FileNotFoundException { + super(file); + } + + @Override + public void write(int b) throws IOException { + if (!abortFlag) { + super.write(b); + } + } + + @Override + public void write(byte[] b) throws IOException { + if (!abortFlag) { + super.write(b); + } + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + if (!abortFlag) { + super.write(b, off, len); + } + } + } +} + From ea676129ea9b9de8b78ac253cefea5645ebb015d Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Fri, 11 Dec 2015 12:01:26 -0800 Subject: [PATCH 080/215] 8068839: newDuration(x) produces incorrect outputs for some values of x Reviewed-by: rriggs, lancea --- .../internal/jaxp/datatype/DurationImpl.java | 6 ++- .../unittest/datatype/JDK8068839Test.java | 47 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 jaxp/test/javax/xml/jaxp/unittest/datatype/JDK8068839Test.java diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/datatype/DurationImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/datatype/DurationImpl.java index b8724a70a34..0b96a733cff 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/datatype/DurationImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/jaxp/datatype/DurationImpl.java @@ -357,7 +357,7 @@ class DurationImpl * The length of the duration in milliseconds. */ protected DurationImpl(final long durationInMilliSeconds) { - + boolean is0x8000000000000000L = false; long l = durationInMilliSeconds; if (l > 0) { @@ -368,6 +368,7 @@ class DurationImpl if (l == 0x8000000000000000L) { // negating 0x8000000000000000L causes an overflow l++; + is0x8000000000000000L = true; } l *= -1; } @@ -406,7 +407,8 @@ class DurationImpl // seconds & milliseconds int2long = (gregorianCalendar.get(Calendar.SECOND) * 1000) - + gregorianCalendar.get(Calendar.MILLISECOND); + + gregorianCalendar.get(Calendar.MILLISECOND) + + (is0x8000000000000000L ? 1 : 0); this.seconds = BigDecimal.valueOf(int2long, 3); } diff --git a/jaxp/test/javax/xml/jaxp/unittest/datatype/JDK8068839Test.java b/jaxp/test/javax/xml/jaxp/unittest/datatype/JDK8068839Test.java new file mode 100644 index 00000000000..636cf680876 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/datatype/JDK8068839Test.java @@ -0,0 +1,47 @@ +/* + * 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. + */ +package datatype; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.Duration; + +import org.testng.Assert; +import org.testng.annotations.Test; + +/* + * @bug 8068839 + * @summary Verifies that Duration's edge cases + */ +public class JDK8068839Test { + + @Test + public void test() throws DatatypeConfigurationException { + DatatypeFactory df = DatatypeFactory.newInstance(); + Duration durationx = df.newDuration(Long.MIN_VALUE); + Assert.assertEquals(durationx.toString(), "-P292277024Y7M16DT7H12M55.808S"); + durationx = df.newDuration(Long.MAX_VALUE); + Assert.assertEquals(durationx.toString(), "P292277024Y7M16DT7H12M55.807S"); + } + +} From a3e2ce543cd9e7c283ef7a44905bbf829e913969 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 11 Dec 2015 15:07:35 -0800 Subject: [PATCH 081/215] 8144997: "IIOException: Field data is past end-of-stream" when calling TIFFImageReader.read() Instead of failing for an IFD entry with bad type or offset, continue with the next entry. Reviewed-by: prr --- .../classes/com/sun/imageio/plugins/tiff/TIFFIFD.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) 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 7c14f8daf85..e8f4a5d05b3 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 @@ -475,9 +475,10 @@ public class TIFFIFD extends TIFFDirectory { int sizeOfType; try { sizeOfType = TIFFTag.getSizeOfType(type); - } catch (IllegalArgumentException e) { - throw new IIOException("Illegal type " + type - + " for tag number " + tagNumber, e); + } catch (IllegalArgumentException ignored) { + // Continue with the next IFD entry. + stream.skipBytes(4); + continue; } int count = (int)stream.readUnsignedInt(); @@ -524,7 +525,7 @@ public class TIFFIFD extends TIFFDirectory { // Check whether the the field value is within the stream. if (haveStreamLength && offset + size > streamLength) { - throw new IIOException("Field data is past end-of-stream"); + continue; } // Add a TIFFIFDEntry as a placeholder. This avoids a mark, From 82c454ff4a33428722d3ebfbfd90b3269df65f23 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Fri, 11 Dec 2015 17:01:01 -0800 Subject: [PATCH 082/215] 8144952: add wildcards to the Map.ofEntries() method Reviewed-by: darcy, psandoz, chegar --- jdk/src/java.base/share/classes/java/util/Map.java | 4 ++-- jdk/test/java/util/Map/MapFactories.java | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/Map.java b/jdk/src/java.base/share/classes/java/util/Map.java index f958607dfc5..0967523eba3 100644 --- a/jdk/src/java.base/share/classes/java/util/Map.java +++ b/jdk/src/java.base/share/classes/java/util/Map.java @@ -1670,9 +1670,9 @@ public interface Map { */ @SafeVarargs @SuppressWarnings("varargs") - static Map ofEntries(Entry... entries) { + static Map ofEntries(Entry... entries) { Map map = new HashMap<>(entries.length * 4 / 3 + 1); // throws NPE if entries is null - for (Entry e : entries) { + for (Entry e : entries) { // next line throws NPE if e is null map.put(Objects.requireNonNull(e.getKey()), Objects.requireNonNull(e.getValue())); } diff --git a/jdk/test/java/util/Map/MapFactories.java b/jdk/test/java/util/Map/MapFactories.java index 1bdb020680d..b8ff0c9f3f2 100644 --- a/jdk/test/java/util/Map/MapFactories.java +++ b/jdk/test/java/util/Map/MapFactories.java @@ -377,4 +377,13 @@ public class MapFactories { assertEquals(sie.toString(), kvh1.toString()); } + // compile-time test of wildcards + @Test + public void entryWildcardTests() { + Map.Entry e1 = Map.entry(1, 2.0); + Map.Entry e2 = Map.entry(3.0f, 4L); + Map map = Map.ofEntries(e1, e2); + assertEquals(map.size(), 2); + } + } From 3d4ea51ab10f16706fcea9c0ccb8151dbe59387e Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Fri, 11 Dec 2015 19:06:40 -0800 Subject: [PATCH 083/215] 8140470: javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java failed with AccessControlException Reviewed-by: mullan --- .../crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/jdk/test/javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java b/jdk/test/javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java index 014a7a6ab38..ca3be869c4d 100644 --- a/jdk/test/javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java +++ b/jdk/test/javax/xml/crypto/dsig/SecurityManager/XMLDSigWithSecMgr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -33,8 +33,6 @@ import java.io.*; import java.net.*; import java.security.KeyPair; import java.security.KeyPairGenerator; -import java.security.Policy; -import java.security.URIParameter; import java.util.ArrayList; import java.util.Collections; import javax.xml.crypto.dsig.*; @@ -115,10 +113,8 @@ public class XMLDSigWithSecMgr implements Runnable { // the policy only grants this test SocketPermission to accept, resolve // and connect to localhost so that it can dereference 2nd reference - URI policyURI = - new File(System.getProperty("test.src", "."), "policy").toURI(); - Policy.setPolicy - (Policy.getInstance("JavaPolicy", new URIParameter(policyURI))); + System.setProperty("java.security.policy", + System.getProperty("test.src", ".") + File.separator + "policy"); System.setSecurityManager(new SecurityManager()); try { From 2a1775f3b1720236cb262f077bfec92d84465db8 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Sun, 13 Dec 2015 15:10:13 +0100 Subject: [PATCH 084/215] 8145007: Pattern splitAsStream is not late binding as required by the specification Reviewed-by: chegar, psandoz --- .../classes/java/util/regex/Pattern.java | 19 +++++++++---------- .../java/util/regex/PatternStreamTest.java | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/regex/Pattern.java b/jdk/src/java.base/share/classes/java/util/regex/Pattern.java index e4f64db438a..3a6ac6f56a8 100644 --- a/jdk/src/java.base/share/classes/java/util/regex/Pattern.java +++ b/jdk/src/java.base/share/classes/java/util/regex/Pattern.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -5814,7 +5814,7 @@ NEXT: while (i <= last) { */ public Stream splitAsStream(final CharSequence input) { class MatcherIterator implements Iterator { - private final Matcher matcher; + private Matcher matcher; // The start position of the next sub-sequence of input // when current == input.length there are no more elements private int current; @@ -5823,14 +5823,6 @@ NEXT: while (i <= last) { // > 0 if there are N next empty elements private int emptyElementCount; - MatcherIterator() { - this.matcher = matcher(input); - // If the input is an empty string then the result can only be a - // stream of the input. Induce that by setting the empty - // element count to 1 - this.emptyElementCount = input.length() == 0 ? 1 : 0; - } - public String next() { if (!hasNext()) throw new NoSuchElementException(); @@ -5846,6 +5838,13 @@ NEXT: while (i <= last) { } public boolean hasNext() { + if (matcher == null) { + matcher = matcher(input); + // If the input is an empty string then the result can only be a + // stream of the input. Induce that by setting the empty + // element count to 1 + emptyElementCount = input.length() == 0 ? 1 : 0; + } if (nextElement != null || emptyElementCount > 0) return true; diff --git a/jdk/test/java/util/regex/PatternStreamTest.java b/jdk/test/java/util/regex/PatternStreamTest.java index 349faad034a..1ac3bfd23e8 100644 --- a/jdk/test/java/util/regex/PatternStreamTest.java +++ b/jdk/test/java/util/regex/PatternStreamTest.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8016846 8024341 8071479 + * @bug 8016846 8024341 8071479 8145006 * @summary Unit tests stream and lambda-based methods on Pattern and Matcher * @library ../stream/bootlib/java.base * @build java.util.stream.OpTestCase @@ -42,6 +42,7 @@ import java.util.function.Supplier; import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.LambdaTestHelpers; import java.util.stream.OpTestCase; import java.util.stream.Stream; @@ -185,6 +186,20 @@ public class PatternStreamTest extends OpTestCase { .exercise(); } + @Test + public void testLateBinding() { + Pattern pattern = Pattern.compile(","); + + StringBuilder sb = new StringBuilder("a,b,c,d,e"); + Stream stream = pattern.splitAsStream(sb); + sb.setLength(3); + assertEquals(Arrays.asList("a", "b"), stream.collect(Collectors.toList())); + + stream = pattern.splitAsStream(sb); + sb.append(",f,g"); + assertEquals(Arrays.asList("a", "b", "f", "g"), stream.collect(Collectors.toList())); + } + public void testFailfastMatchResults() { Pattern p = Pattern.compile("X"); Matcher m = p.matcher("XX"); From 38302301fd9b93956904ff3590e3700c26aab570 Mon Sep 17 00:00:00 2001 From: Shinya Yoshida Date: Sun, 13 Dec 2015 15:20:35 +0100 Subject: [PATCH 085/215] 8144675: Add a filtering collector Reviewed-by: psandoz, smarks --- .../classes/java/util/stream/Collectors.java | 49 +++++++++++++++++- .../java/util/stream/CollectorsTest.java | 50 ++++++++++++++++++- 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java index c3be0d97eb8..97e05c326ec 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java +++ b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java @@ -434,7 +434,7 @@ public final class Collectors { * stream returned by mapper * @return a collector which applies the mapping function to the input * elements and provides the flat mapped results to the downstream collector - * @since 1.9 + * @since 9 */ public static Collector flatMapping(Function> mapper, @@ -451,6 +451,53 @@ public final class Collectors { downstream.characteristics()); } + /** + * Adapts a {@code Collector} to one accepting elements of the same type + * {@code T} by applying the predicate to each input element and only + * accumulating if the predicate returns {@code true}. + * + * @apiNote + * The {@code filtering()} collectors are most useful when used in a + * multi-level reduction, such as downstream of a {@code groupingBy} or + * {@code partitioningBy}. For example, given a stream of + * {@code Employee}, to accumulate the employees in each department that have a + * salary above a certain threshold: + *
{@code
+     *     Map> wellPaidEmployeesByDepartment
+     *         = employees.stream().collect(groupingBy(Employee::getDepartment,
+     *                                              filtering(e -> e.getSalary() > 2000, toSet())));
+     * }
+ * A filtering collector differs from a stream's {@code filter()} operation. + * In this example, suppose there are no employees whose salary is above the + * threshold in some department. Using a filtering collector as shown above + * would result in a mapping from that department to an empty {@code Set}. + * If a stream {@code filter()} operation were done instead, there would be + * no mapping for that department at all. + * + * @param the type of the input elements + * @param intermediate accumulation type of the downstream collector + * @param result type of collector + * @param predicate a predicate to be applied to the input elements + * @param downstream a collector which will accept values that match the + * predicate + * @return a collector which applies the predicate to the input elements + * and provides matching elements to the downstream collector + * @since 9 + */ + public static + Collector filtering(Predicate predicate, + Collector downstream) { + BiConsumer downstreamAccumulator = downstream.accumulator(); + return new CollectorImpl<>(downstream.supplier(), + (r, t) -> { + if (predicate.test(t)) { + downstreamAccumulator.accept(r, t); + } + }, + downstream.combiner(), downstream.finisher(), + downstream.characteristics()); + } + /** * Adapts a {@code Collector} to perform an additional finishing * transformation. For example, one could adapt the {@link #toList()} diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectorsTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectorsTest.java index 07fa5bcb5cf..d07b6eba4a7 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectorsTest.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/CollectorsTest.java @@ -56,6 +56,7 @@ import org.testng.annotations.Test; import static java.util.stream.Collectors.collectingAndThen; import static java.util.stream.Collectors.flatMapping; +import static java.util.stream.Collectors.filtering; import static java.util.stream.Collectors.groupingBy; import static java.util.stream.Collectors.groupingByConcurrent; import static java.util.stream.Collectors.mapping; @@ -72,7 +73,7 @@ import static java.util.stream.LambdaTestHelpers.mDoubler; /* * @test - * @bug 8071600 + * @bug 8071600 8144675 * @summary Test for collectors. */ public class CollectorsTest extends OpTestCase { @@ -118,6 +119,23 @@ public class CollectorsTest extends OpTestCase { } } + static class FilteringAssertion extends CollectorAssertion { + private final Predicate filter; + private final CollectorAssertion downstream; + + public FilteringAssertion(Predicate filter, CollectorAssertion downstream) { + this.filter = filter; + this.downstream = downstream; + } + + @Override + void assertValue(R value, Supplier> source, boolean ordered) throws ReflectiveOperationException { + downstream.assertValue(value, + () -> source.get().filter(filter), + ordered); + } + } + static class GroupingByAssertion> extends CollectorAssertion { private final Class clazz; private final Function classifier; @@ -550,6 +568,36 @@ public class CollectorsTest extends OpTestCase { new ToListAssertion<>()))); } + @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class) + public void testGroupingByWithFiltering(String name, TestData.OfRef data) throws ReflectiveOperationException { + Function classifier = i -> i % 3; + Predicate filteringByMod2 = i -> i % 2 == 0; + Predicate filteringByUnder100 = i -> i % 2 < 100; + Predicate filteringByTrue = i -> true; + Predicate filteringByFalse = i -> false; + + exerciseMapCollection(data, + groupingBy(classifier, filtering(filteringByMod2, toList())), + new GroupingByAssertion<>(classifier, HashMap.class, + new FilteringAssertion<>(filteringByMod2, + new ToListAssertion<>()))); + exerciseMapCollection(data, + groupingBy(classifier, filtering(filteringByUnder100, toList())), + new GroupingByAssertion<>(classifier, HashMap.class, + new FilteringAssertion<>(filteringByUnder100, + new ToListAssertion<>()))); + exerciseMapCollection(data, + groupingBy(classifier, filtering(filteringByTrue, toList())), + new GroupingByAssertion<>(classifier, HashMap.class, + new FilteringAssertion<>(filteringByTrue, + new ToListAssertion<>()))); + exerciseMapCollection(data, + groupingBy(classifier, filtering(filteringByFalse, toList())), + new GroupingByAssertion<>(classifier, HashMap.class, + new FilteringAssertion<>(filteringByFalse, + new ToListAssertion<>()))); + } + @Test(dataProvider = "StreamTestData", dataProviderClass = StreamTestDataProvider.class) public void testTwoLevelGroupingBy(String name, TestData.OfRef data) throws ReflectiveOperationException { Function classifier = i -> i % 6; From 062dc5fdee6a637105d8e28da75eaa9045d6ba4d Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Mon, 14 Dec 2015 11:51:33 +0100 Subject: [PATCH 086/215] 8145008: Add libelf package to Linux devkit Reviewed-by: ihse --- make/devkit/Tools.gmk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index e5cb19ff701..aa7482a8f20 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -82,7 +82,9 @@ RPM_LIST := \ libXi libXi-devel \ libXdmcp libXdmcp-devel \ libXau libXau-devel \ - libgcc + libgcc \ + elfutils elfutils-devel \ + elfutils-libelf elfutils-libelf-devel ifeq ($(ARCH),x86_64) From 64634dc9a4d34a43577e8e26696ec5195d52be8d Mon Sep 17 00:00:00 2001 From: Michael Haupt Date: Mon, 14 Dec 2015 14:02:59 +0100 Subject: [PATCH 087/215] 8144221: fix Nashorn shebang argument handling on Mac/Linux Reviewed-by: jlaskey, lagergren --- nashorn/make/build.xml | 10 +- .../internal/runtime/ScriptingFunctions.java | 13 +- .../classes/jdk/nashorn/tools/Shell.java | 133 +++++++-------- nashorn/test/script/nosecurity/JDK-8144221.js | 155 ++++++++++++++++++ .../script/nosecurity/JDK-8144221.js.EXPECTED | 68 ++++++++ .../test/script/nosecurity/os-not-windows.js | 37 +++++ 6 files changed, 347 insertions(+), 69 deletions(-) create mode 100644 nashorn/test/script/nosecurity/JDK-8144221.js create mode 100644 nashorn/test/script/nosecurity/JDK-8144221.js.EXPECTED create mode 100644 nashorn/test/script/nosecurity/os-not-windows.js diff --git a/nashorn/make/build.xml b/nashorn/make/build.xml index 9f5d48cae50..32d08ad694b 100644 --- a/nashorn/make/build.xml +++ b/nashorn/make/build.xml @@ -48,12 +48,12 @@ - + - + diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java index eb4fb4dfa56..5f849ea38b5 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java @@ -278,9 +278,8 @@ public final class ScriptingFunctions { * @param str a {@link String} to tokenize. * @return a {@link List} of {@link String}s representing the tokens that * constitute the string. - * @throws IOException in case {@link StreamTokenizer#nextToken()} raises it. */ - public static List tokenizeString(final String str) throws IOException { + public static List tokenizeString(final String str) { final StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(str)); tokenizer.resetSyntax(); tokenizer.wordChars(0, 255); @@ -290,7 +289,7 @@ public final class ScriptingFunctions { tokenizer.quoteChar('\''); final List tokenList = new ArrayList<>(); final StringBuilder toAppend = new StringBuilder(); - while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) { + while (nextToken(tokenizer) != StreamTokenizer.TT_EOF) { final String s = tokenizer.sval; // The tokenizer understands about honoring quoted strings and recognizes // them as one token that possibly contains multiple space-separated words. @@ -309,4 +308,12 @@ public final class ScriptingFunctions { } return tokenList; } + + private static int nextToken(final StreamTokenizer tokenizer) { + try { + return tokenizer.nextToken(); + } catch (final IOException ioe) { + return StreamTokenizer.TT_EOF; + } + } } diff --git a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java index 41669f814ba..e92eca362b9 100644 --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java @@ -25,23 +25,6 @@ package jdk.nashorn.tools; -import static jdk.nashorn.internal.runtime.Source.sourceFor; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; -import java.util.stream.Collectors; - import jdk.nashorn.api.scripting.NashornException; import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.Compiler.CompilationPhases; @@ -60,10 +43,32 @@ import jdk.nashorn.internal.runtime.ScriptEnvironment; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; +import jdk.nashorn.internal.runtime.ScriptingFunctions; import jdk.nashorn.internal.runtime.Symbol; import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator; import jdk.nashorn.internal.runtime.options.Options; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; + +import static jdk.nashorn.internal.runtime.Source.sourceFor; + /** * Command line Shell for processing JavaScript files. */ @@ -203,8 +208,7 @@ public class Shell implements PartialParser { // parse options if (args != null) { try { - // FIXME: preprocessArgs does not yet work fine - final String[] prepArgs = args; // preprocessArgs(args); + final String[] prepArgs = preprocessArgs(args); options.process(prepArgs); } catch (final IllegalArgumentException e) { werr.println(bundle.getString("shell.usage")); @@ -236,35 +240,53 @@ public class Shell implements PartialParser { } /** - * Preprocess the command line arguments passed in by the shell. This checks, for each of the arguments, whether it - * can be a file name, and if so, whether the file exists. If the file exists and begins with a shebang line, and - * the arguments on that line are a prefix of {@code args} with the file removed, it is assumed that a script file - * being executed via shebang was found, and it is moved to the appropriate position in the argument list. The first - * such match is used. + * Preprocess the command line arguments passed in by the shell. This method checks, for the first non-option + * argument, whether the file denoted by it begins with a shebang line. If so, it is assumed that execution in + * shebang mode is intended. The consequence of this is that the identified script file will be treated as the + * only script file, and all subsequent arguments will be regarded as arguments to the script. *

- * This method canonicalizes the command line arguments to the form {@code -- }, - * where the last of the {@code scripts} is the one being run in shebang fashion. + * This method canonicalizes the command line arguments to the form {@code