From 0fcb9ffe7520fb9e65e02bbaad60e982b54fba36 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Sun, 6 Sep 2015 10:13:18 +0300 Subject: [PATCH 01/75] 8065151: Support IdealGraphVisualizer in optimized build Reviewed-by: kvn --- hotspot/src/share/vm/opto/c2_globals.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index fb4e2dd8f26..1782abfd0a1 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -374,10 +374,10 @@ \ develop(intx, PrintIdealGraphLevel, 0, \ "Level of detail of the ideal graph printout. " \ - "System-wide value, 0=nothing is printed, 3=all details printed. "\ + "System-wide value, 0=nothing is printed, 4=all details printed. "\ "Level of detail of printouts can be set on a per-method level " \ "as well by using CompileCommand=option.") \ - range(0, 3) \ + range(0, 4) \ \ develop(intx, PrintIdealGraphPort, 4444, \ "Ideal graph printer to network port") \ From 317553031c74d47019b9aefcfaf18b0e2cc4526b Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Mon, 19 Oct 2015 17:52:39 +0300 Subject: [PATCH 02/75] 8139881: Exclude java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java from execution Reviewed-by: kvn --- .../java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java b/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java index 3a97456e1a4..6f4ad86a280 100644 --- a/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java +++ b/jdk/test/java/lang/invoke/LFCaching/LFSingleThreadCachingTest.java @@ -23,6 +23,7 @@ /* * @test LFSingleThreadCachingTest + * @ignore 8129523 * @bug 8046703 * @key randomness * @summary Test verifies that lambda forms are cached when run with single thread From cdd7249f6e1537f9c2b9e26d6a1a80f91e090356 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Fri, 30 Oct 2015 11:12:20 -0400 Subject: [PATCH 03/75] 8139390: Very long classname in jimage causes SIGSEGV Correct issues with ImageNativeSubstrate and JImageReadTest Reviewed-by: mchung --- .../native/libjimage/ImageNativeSubstrate.cpp | 86 +++++++++++++++---- .../share/native/libjimage/jimage.cpp | 29 +++++-- .../jdk/internal/jimage/JImageReadTest.java | 30 ++++++- 3 files changed, 117 insertions(+), 28 deletions(-) diff --git a/jdk/src/java.base/share/native/libjimage/ImageNativeSubstrate.cpp b/jdk/src/java.base/share/native/libjimage/ImageNativeSubstrate.cpp index d2217e4fe62..0f803cb4fa9 100644 --- a/jdk/src/java.base/share/native/libjimage/ImageNativeSubstrate.cpp +++ b/jdk/src/java.base/share/native/libjimage/ImageNativeSubstrate.cpp @@ -26,8 +26,7 @@ #include #include "jni.h" -#include "jni_util.h" -#include "jdk_util.h" + #include "endian.hpp" #include "imageDecompressor.hpp" #include "imageFile.hpp" @@ -39,6 +38,17 @@ extern bool MemoryMapImage; +///////////////////////////////////////////////////////////////////////////// + +// Static function for primitive throw since libjimage is not linked with libjava +static void JNICALL ThrowByName(JNIEnv *env, const char *name, const char *msg) +{ + jclass cls = (env)->FindClass(name); + + if (cls != 0) /* Otherwise an exception has already been thrown */ + (env)->ThrowNew(cls, msg); +} + // jdk.internal.jimage ///////////////////////////////////////////////////////// // Java entry to open an image file for sharing. @@ -446,6 +456,23 @@ JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Fi jlong size = 0; jlong ret = 0; + if (moduleName == NULL) { + ThrowByName(env, "java/lang/NullPointerException", "moduleName"); + return 0; + } + if (version == NULL) { + ThrowByName(env, "java/lang/NullPointerException", "version"); + return 0; + } + if (path == NULL) { + ThrowByName(env, "java/lang/NullPointerException", "path"); + return 0; + } + if (output_size == NULL) { + ThrowByName(env, "java/lang/NullPointerException", "size"); + return 0; + } + do { native_module = env->GetStringUTFChars(moduleName, NULL); if (native_module == NULL) @@ -529,25 +556,47 @@ static bool resourceVisitor(JImageFile* image, // Store if there is room in the array // Concatenate to get full path char fullpath[IMAGE_MAX_PATH]; - fullpath[0] = '\0'; - if (*module != '\0') { - strncpy(fullpath, "/", IMAGE_MAX_PATH - 1); - strncat(fullpath, module, IMAGE_MAX_PATH - 1); - strncat(fullpath, "/", IMAGE_MAX_PATH - 1); + size_t moduleLen = strlen(module); + size_t packageLen = strlen(package); + size_t nameLen = strlen(name); + size_t extLen = strlen(extension); + size_t index; + + if (1 + moduleLen + 1 + packageLen + 1 + nameLen + 1 + extLen + 1 > IMAGE_MAX_PATH) { + ThrowByName(env, "java/lang/InternalError", "concatenated name too long"); + return true; } - if (*package != '\0') { - strncat(fullpath, package, IMAGE_MAX_PATH - 1); - strncat(fullpath, "/", IMAGE_MAX_PATH - 1); + + index = 0; + if (moduleLen > 0) { + fullpath[index++] = '/'; + memcpy(&fullpath[index], module, moduleLen); + index += moduleLen; + fullpath[index++] = '/'; } - strncat(fullpath, name, IMAGE_MAX_PATH - 1); - if (*extension != '\0') { - strncat(fullpath, ".", IMAGE_MAX_PATH - 1); - strncat(fullpath, extension, IMAGE_MAX_PATH - 1); + if (packageLen > 0) { + memcpy(&fullpath[index], package, packageLen); + index += packageLen; + fullpath[index++] = '/'; } + memcpy(&fullpath[index], name, nameLen); + index += nameLen; + if (extLen > 0) { + fullpath[index++] = '.'; + memcpy(&fullpath[index], extension, extLen); + index += extLen; + } + fullpath[index++] = '\0'; + jobject str = env->NewStringUTF(fullpath); - JNU_CHECK_EXCEPTION_RETURN(env, true); + if (env->ExceptionCheck()) { + return true; + } + env->SetObjectArrayElement(vdata->array, vdata->size, str); - JNU_CHECK_EXCEPTION_RETURN(env, true); + if (env->ExceptionCheck()) { + return true; + } } vdata->size++; // always count so the total size is returned return true; @@ -584,7 +633,10 @@ JNIEXPORT jstring JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1 jstring module = NULL; native_package = env->GetStringUTFChars(package_name, NULL); - JNU_CHECK_EXCEPTION_RETURN(env, NULL); + if (env->ExceptionCheck()) { + return NULL; + } + native_module = JIMAGE_PackageToModule((JImageFile*) jimageHandle, native_package); if (native_module != NULL) { diff --git a/jdk/src/java.base/share/native/libjimage/jimage.cpp b/jdk/src/java.base/share/native/libjimage/jimage.cpp index cd09ffa2339..371cb1dc706 100644 --- a/jdk/src/java.base/share/native/libjimage/jimage.cpp +++ b/jdk/src/java.base/share/native/libjimage/jimage.cpp @@ -102,14 +102,29 @@ extern "C" const char* JIMAGE_PackageToModule(JImageFile* image, const char* pac extern "C" JImageLocationRef JIMAGE_FindResource(JImageFile* image, const char* module_name, const char* version, const char* name, jlong* size) { - ImageLocation location; - char fullpath[IMAGE_MAX_PATH]; - // Concatenate to get full path - strncpy(fullpath, "/", IMAGE_MAX_PATH - 1); - strncat(fullpath, module_name, IMAGE_MAX_PATH - 1); - strncat(fullpath, "/", IMAGE_MAX_PATH - 1); - strncat(fullpath, name, IMAGE_MAX_PATH - 1); + char fullpath[IMAGE_MAX_PATH]; + size_t moduleNameLen = strlen(module_name); + size_t nameLen = strlen(name); + size_t index; + + // TBD: assert(moduleNameLen > 0 && "module name must be non-empty"); + assert(nameLen > 0 && "name must non-empty"); + + // If the concatenated string is too long for the buffer, return not found + if (1 + moduleNameLen + 1 + nameLen + 1 > IMAGE_MAX_PATH) { + return 0L; + } + + index = 0; + fullpath[index++] = '/'; + memcpy(&fullpath[index], module_name, moduleNameLen); + index += moduleNameLen; + fullpath[index++] = '/'; + memcpy(&fullpath[index], name, nameLen); + index += nameLen; + fullpath[index++] = '\0'; + JImageLocationRef loc = (JImageLocationRef) ((ImageFileReader*) image)->find_location_index(fullpath, (u8*) size); return loc; diff --git a/jdk/test/jdk/internal/jimage/JImageReadTest.java b/jdk/test/jdk/internal/jimage/JImageReadTest.java index 910c35aec4a..82df8c83384 100644 --- a/jdk/test/jdk/internal/jimage/JImageReadTest.java +++ b/jdk/test/jdk/internal/jimage/JImageReadTest.java @@ -22,7 +22,9 @@ */ /* + * @test * @modules java.base/jdk.internal.jimage + * @run testng JImageReadTest * @summary Unit test for libjimage JIMAGE_Open/Read/Close */ @@ -57,8 +59,7 @@ public class JImageReadTest { {"java.base", "java/lang/String.class"}, {"java.base", "java/lang/Object.class"}, {"java.base", "sun/reflect/generics/tree/TypeArgument.class"}, - {"jdk.jdeps", "com/sun/tools/javap/StackMapWriter$StackMapBuilder.class"}, - {"jdk.hotspot.agent", "sa.properties"}, + {"java.base", "sun/net/www/content-types.properties"}, {"java.logging", "java/util/logging/Logger.class"}, {"java.base", "java/NOSUCHCLASS/yyy.class"}, // non-existent {"NOSUCHMODULE", "java/lang/Class.class"}, // non-existent @@ -165,8 +166,10 @@ public class JImageReadTest { int count = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle, names); System.out.printf(" count: %d, a class: %s\n", count, names[0]); - Assert.assertTrue(max > 31000, - "missing entries, should be more than 31000, reported: " + count); + int minEntryCount = 16000; + Assert.assertTrue(max > minEntryCount, + "missing entries, should be more than " + minEntryCount + + ", reported: " + count); Assert.assertTrue(count == max, "unexpected count of entries, count: " + count + ", max: " + max); @@ -310,6 +313,7 @@ public class JImageReadTest { static boolean isMetaName(String name) { return name.startsWith("/modules") || name.startsWith("/packages") + || name.startsWith("META-INF/services") || name.equals("bootmodules.jdata"); } @@ -362,6 +366,24 @@ public class JImageReadTest { System.out.printf(" %s: %d names%n", fname, names.length); } + @Test + static void test5_nameTooLong() throws IOException { + long[] size = new long[1]; + String moduleName = "FictiousModuleName"; + String className = String.format("A%09999d", 1); + + long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile); + Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle); + + long locationHandle = + ImageNativeSubstrate.JIMAGE_FindResource(jimageHandle, + moduleName, "9.0", className, size); + + Assert.assertEquals(0, locationHandle, "Too long name should have failed"); + + ImageNativeSubstrate.JIMAGE_Close(jimageHandle); + } + // main method to run standalone from jtreg @Test(enabled=false) From 638270935d3c48b079f423030a0d2da7ca240ae1 Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Mon, 2 Nov 2015 14:57:04 +0100 Subject: [PATCH 04/75] 8140514: [TESTBUG] enable sun/security/pkcs11 tests on Linux/ppc64 Reviewed-by: wetmore --- jdk/test/sun/security/pkcs11/PKCS11Test.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/test/sun/security/pkcs11/PKCS11Test.java b/jdk/test/sun/security/pkcs11/PKCS11Test.java index 6ee011a294d..1e738601104 100644 --- a/jdk/test/sun/security/pkcs11/PKCS11Test.java +++ b/jdk/test/sun/security/pkcs11/PKCS11Test.java @@ -539,6 +539,7 @@ public abstract class PKCS11Test { osMap.put("Linux-amd64-64", new String[]{ "/usr/lib/x86_64-linux-gnu/", "/usr/lib/x86_64-linux-gnu/nss/", "/usr/lib64/"}); + osMap.put("Linux-ppc64-64", new String[]{"/usr/lib64/"}); osMap.put("Windows-x86-32", new String[]{ PKCS11_BASE + "/nss/lib/windows-i586/".replace('/', SEP)}); osMap.put("Windows-amd64-64", new String[]{ From 5710e3c7543e7effef4cea30bad8b66f3c31a627 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Mon, 2 Nov 2015 08:46:19 -0800 Subject: [PATCH 05/75] 8062006: Add a new locale data name "COMPAT" for java.locale.providers system property to reduce ambiguity Reviewed-by: okutsu --- .../java/util/spi/LocaleServiceProvider.java | 14 ++++---- .../provider/LocaleProviderAdapter.java | 4 +++ jdk/test/java/util/Locale/LocaleProviders.sh | 33 ++++++++++++------- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/jdk/src/java.base/share/classes/java/util/spi/LocaleServiceProvider.java b/jdk/src/java.base/share/classes/java/util/spi/LocaleServiceProvider.java index 582bbba95c8..a9bc8863ded 100644 --- a/jdk/src/java.base/share/classes/java/util/spi/LocaleServiceProvider.java +++ b/jdk/src/java.base/share/classes/java/util/spi/LocaleServiceProvider.java @@ -123,25 +123,27 @@ import java.util.Locale; *
    *
  • "CLDR": A provider based on Unicode Consortium's * CLDR Project. - *
  • "JRE": represents the locale sensitive services that is compatible - * with the prior JDK releases (same with JDK8's "JRE"). + *
  • "COMPAT": represents the locale sensitive services that is compatible + * with the prior JDK releases up to JDK8 (same as JDK8's "JRE"). *
  • "SPI": represents the locale sensitive services implementing the subclasses of * this {@code LocaleServiceProvider} class. *
  • "HOST": A provider that reflects the user's custom settings in the * underlying operating system. This provider may not be available, depending * on the Java Runtime Environment implementation. + *
  • "JRE": represents a synonym to "COMPAT". This name + * is deprecated and will be removed in the future release of JDK. *
*

* For example, if the following is specified in the property: *

- * java.locale.providers=SPI,CLDR,JRE
+ * java.locale.providers=SPI,CLDR,COMPAT
  * 
* the locale sensitive services in the SPI providers are looked up first. If the * desired locale sensitive service is not available, then the runtime looks for CLDR, - * JRE in that order. + * COMPAT in that order. *

- * The default order for looking up the preferred locale providers is "CLDR,JRE", - * so specifying "CLDR,JRE" is identical to the default behavior. Applications which + * The default order for looking up the preferred locale providers is "CLDR,COMPAT", + * so specifying "CLDR,COMPAT" is identical to the default behavior. Applications which * require implementations of the locale sensitive services must explicitly specify * "SPI" in order for the Java runtime to load them from the classpath. * diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java index 0844a701594..c17856ffe9a 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java @@ -124,6 +124,10 @@ public abstract class LocaleProviderAdapter { if (order != null && order.length() != 0) { String[] types = order.split(","); for (String type : types) { + type = type.trim().toUpperCase(Locale.ROOT); + if (type.equals("COMPAT")) { + type = "JRE"; + } try { Type aType = Type.valueOf(type.trim().toUpperCase(Locale.ROOT)); if (!typeList.contains(aType)) { diff --git a/jdk/test/java/util/Locale/LocaleProviders.sh b/jdk/test/java/util/Locale/LocaleProviders.sh index 5e1b79383f5..fb8043e21c3 100644 --- a/jdk/test/java/util/Locale/LocaleProviders.sh +++ b/jdk/test/java/util/Locale/LocaleProviders.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 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 @@ -24,7 +24,7 @@ # # @test # @bug 6336885 7196799 7197573 7198834 8000245 8000615 8001440 8008577 -# 8010666 8013086 8013233 8013903 8015960 8028771 +# 8010666 8013086 8013233 8013903 8015960 8028771 8062006 # @summary tests for "java.locale.providers" system property # @compile -XDignore.symbol.file LocaleProviders.java # @run shell/timeout=600 LocaleProviders.sh @@ -182,7 +182,7 @@ PARAM1=JRE if [ "${DEFLANG}" != "en" ] && [ "${DEFFMTLANG}" != "en" ]; then PARAM2=en PARAM3=US -elif [ "${DEFLANG}" != "ja" ] && [ "${DEFFMTLANG}" != "ja" ]; then +elif [ "${DEFLANG}" != "ja" ] && [ "${DEFFMTLANG}" != "ja" ]; then PARAM2=ja PARAM3=JP else @@ -200,6 +200,8 @@ PARAM2=en PARAM3=US SPICLASSES= runTest +PREFLIST=SPI,COMPAT +runTest # testing the order, variaton #1. This assumes en_GB DateFormat data are available both in JRE & CLDR METHODNAME=adapterTest @@ -209,6 +211,8 @@ PARAM2=en PARAM3=GB SPICLASSES= runTest +PREFLIST=CLDR,COMPAT +runTest # testing the order, variaton #2. This assumes en_GB DateFormat data are available both in JRE & CLDR METHODNAME=adapterTest @@ -218,6 +222,8 @@ PARAM2=en PARAM3=GB SPICLASSES= runTest +PREFLIST=COMPAT,CLDR +runTest # testing the order, variaton #3 for non-existent locale in JRE assuming "haw" is not in JRE. METHODNAME=adapterTest @@ -227,6 +233,8 @@ PARAM2=haw PARAM3= SPICLASSES= runTest +PREFLIST=COMPAT,CLDR +runTest # testing the order, variaton #4 for the bug 7196799. CLDR's "zh" data should be used in "zh_CN" METHODNAME=adapterTest @@ -275,6 +283,8 @@ PARAM2= PARAM3= SPICLASSES=${SPIDIR} runTest +PREFLIST=COMPAT +runTest # testing 8000615 fix. METHODNAME=tzNameTest @@ -284,6 +294,8 @@ PARAM2= PARAM3= SPICLASSES=${SPIDIR} runTest +PREFLIST=COMPAT +runTest # testing 8001440 fix. METHODNAME=bug8001440Test @@ -314,6 +326,8 @@ PARAM2=JP PARAM3= SPICLASSES=${SPIDIR} runTest +PREFLIST=COMPAT,SPI +runTest # testing 8013903 fix. (Windows only) METHODNAME=bug8013903Test @@ -323,12 +337,9 @@ PARAM2= PARAM3= SPICLASSES= runTest -METHODNAME=bug8013903Test PREFLIST=HOST -PARAM1= -PARAM2= -PARAM3= -SPICLASSES= +runTest +PREFLIST=HOST,COMPAT runTest # testing 8027289 fix, if the platform format default is zh_CN @@ -342,12 +353,10 @@ if [ "${DEFFMTLANG}" = "zh" ] && [ "${DEFFMTCTRY}" = "CN" ]; then PARAM3= SPICLASSES= runTest - METHODNAME=bug8027289Test + PREFLIST=COMPAT,HOST + runTest PREFLIST=HOST PARAM1=00A5 - PARAM2= - PARAM3= - SPICLASSES= runTest fi From dc711078d4f29a414c91750e222f82fabe5ca92e Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Wed, 23 Sep 2015 14:25:02 +0200 Subject: [PATCH 06/75] 8139727: Define ConstructorParameters annotation type for MXBeans Reviewed-by: alanb, mchung, dfuchs, abuckley, plevart, mr --- .../DefaultMXBeanMappingFactory.java | 58 ++++++---- .../management/ConstructorParameters.java | 76 +++++++++++++ .../classes/javax/management/MXBean.java | 42 ++++--- .../Introspector/AnnotationSecurityTest.java | 8 +- .../management/Introspector/Described.java | 4 +- .../management/Introspector/DescribedMX.java | 4 +- .../LegacyConstructorPropertiesTest.java | 106 ++++++++++++++++++ .../mxbean/AmbiguousConstructorTest.java | 18 ++- .../mxbean/ExceptionDiagnosisTest.java | 7 +- .../javax/management/mxbean/LeakTest.java | 3 +- .../javax/management/mxbean/MXBeanTest.java | 3 +- .../management/mxbean/PropertyNamesTest.java | 13 +-- .../javax/management/mxbean/TigerMXBean.java | 6 +- 13 files changed, 272 insertions(+), 76 deletions(-) create mode 100644 jdk/src/java.management/share/classes/javax/management/ConstructorParameters.java create mode 100644 jdk/test/javax/management/Introspector/LegacyConstructorPropertiesTest.java diff --git a/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java b/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java index 0b2835f9ee0..c322ed4f028 100644 --- a/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java +++ b/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java @@ -60,6 +60,7 @@ import java.util.WeakHashMap; import javax.management.JMX; import javax.management.ObjectName; +import javax.management.ConstructorParameters; import javax.management.openmbean.ArrayType; import javax.management.openmbean.CompositeData; import javax.management.openmbean.CompositeDataInvocationHandler; @@ -1132,8 +1133,8 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { } /** Builder for when the target class has a constructor that is - annotated with @ConstructorProperties so we can see the correspondence - to getters. */ + annotated with {@linkplain ConstructorParameters @ConstructorParameters} + or {@code @ConstructorProperties} so we can see the correspondence to getters. */ private static final class CompositeBuilderViaConstructor extends CompositeBuilder { @@ -1141,10 +1142,19 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { super(targetClass, itemNames); } - String applicable(Method[] getters) throws InvalidObjectException { - if (!JavaBeansAccessor.isAvailable()) - return "@ConstructorProperties annotation not available"; + private String[] getConstPropValues(Constructor ctr) { + // is constructor annotated by javax.management.ConstructorParameters ? + ConstructorParameters ctrProps = ctr.getAnnotation(ConstructorParameters.class); + if (ctrProps != null) { + return ctrProps.value(); + } else { + // try the legacy java.beans.ConstructorProperties annotation + String[] vals = JavaBeansAccessor.getConstructorPropertiesValue(ctr); + return vals; + } + } + String applicable(Method[] getters) throws InvalidObjectException { Class targetClass = getTargetClass(); Constructor[] constrs = targetClass.getConstructors(); @@ -1152,12 +1162,13 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { List> annotatedConstrList = newList(); for (Constructor constr : constrs) { if (Modifier.isPublic(constr.getModifiers()) - && JavaBeansAccessor.getConstructorPropertiesValue(constr) != null) + && getConstPropValues(constr) != null) annotatedConstrList.add(constr); } if (annotatedConstrList.isEmpty()) - return "no constructor has @ConstructorProperties annotation"; + return "no constructor has either @ConstructorParameters " + + "or @ConstructorProperties annotation"; annotatedConstructors = newList(); @@ -1181,13 +1192,17 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { // so we can test unambiguity. Set getterIndexSets = newSet(); for (Constructor constr : annotatedConstrList) { - String[] propertyNames = JavaBeansAccessor.getConstructorPropertiesValue(constr); + String annotationName = + constr.isAnnotationPresent(ConstructorParameters.class) ? + "@ConstructorParameters" : "@ConstructorProperties"; + + String[] propertyNames = getConstPropValues(constr); Type[] paramTypes = constr.getGenericParameterTypes(); if (paramTypes.length != propertyNames.length) { final String msg = "Number of constructor params does not match " + - "@ConstructorProperties annotation: " + constr; + annotationName + " annotation: " + constr; throw new InvalidObjectException(msg); } @@ -1200,7 +1215,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { String propertyName = propertyNames[i]; if (!getterMap.containsKey(propertyName)) { String msg = - "@ConstructorProperties includes name " + propertyName + + annotationName + " includes name " + propertyName + " which does not correspond to a property"; for (String getterName : getterMap.keySet()) { if (getterName.equalsIgnoreCase(propertyName)) { @@ -1215,7 +1230,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { paramIndexes[getterIndex] = i; if (present.get(getterIndex)) { final String msg = - "@ConstructorProperties contains property " + + annotationName + " contains property " + propertyName + " more than once: " + constr; throw new InvalidObjectException(msg); } @@ -1224,7 +1239,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { Type propertyType = getter.getGenericReturnType(); if (!propertyType.equals(paramTypes[i])) { final String msg = - "@ConstructorProperties gives property " + propertyName + + annotationName + " gives property " + propertyName + " of type " + propertyType + " for parameter " + " of type " + paramTypes[i] + ": " + constr; throw new InvalidObjectException(msg); @@ -1233,7 +1248,8 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { if (!getterIndexSets.add(present)) { final String msg = - "More than one constructor has a @ConstructorProperties " + + "More than one constructor has " + + "@ConstructorParameters or @ConstructorProperties " + "annotation with this set of names: " + Arrays.toString(propertyNames); throw new InvalidObjectException(msg); @@ -1252,10 +1268,10 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { * just the bigger constructor. * * The algorithm here is quadratic in the number of constructors - * with a @ConstructorProperties annotation. Typically this corresponds - * to the number of versions of the class there have been. Ten - * would already be a large number, so although it's probably - * possible to have an O(n lg n) algorithm it wouldn't be + * with a @ConstructorParameters or @ConstructructorProperties annotation. + * Typically this corresponds to the number of versions of the class + * there have been. Ten would already be a large number, so although + * it's probably possible to have an O(n lg n) algorithm it wouldn't be * worth the complexity. */ for (BitSet a : getterIndexSets) { @@ -1272,8 +1288,9 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { i = u.nextSetBit(i+1)) names.add(itemNames[i]); final String msg = - "Constructors with @ConstructorProperties annotation " + - " would be ambiguous for these items: " + + "Constructors with @ConstructorParameters or " + + "@ConstructorProperties annotation " + + "would be ambiguous for these items: " + names; throw new InvalidObjectException(msg); } @@ -1310,7 +1327,8 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory { if (max == null) { final String msg = - "No constructor has a @ConstructorProperties for this set of " + + "No constructor has either @ConstructorParameters " + + "or @ConstructorProperties annotation for this set of " + "items: " + ct.keySet(); throw new InvalidObjectException(msg); } diff --git a/jdk/src/java.management/share/classes/javax/management/ConstructorParameters.java b/jdk/src/java.management/share/classes/javax/management/ConstructorParameters.java new file mode 100644 index 00000000000..d3d447e2a53 --- /dev/null +++ b/jdk/src/java.management/share/classes/javax/management/ConstructorParameters.java @@ -0,0 +1,76 @@ +/* + * 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 + * 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 javax.management; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +/** + *

+ * An annotation on a constructor that shows how the parameters of + * that constructor correspond to the constructed object's getter + * methods. For example: + *

+ *
+ *
+ *         public class MemoryUsage {
+ *             // standard JavaBean conventions with getters
+ *             @ConstructorParameters({"init", "used", "committed", "max"})
+ *             public MemoryUsage(long init, long used,
+ *                                long committed, long max) {...}
+ *             public long getInit() {...}
+ *             public long getUsed() {...}
+ *             public long getCommitted() {...}
+ *             public long getMax() {...}
+ *         }
+ *     
+ *
+ *

+ * The annotation shows that the first parameter of the constructor + * can be retrieved with the {@code getInit()} method, the second one with + * the {@code getUsed()} method, and so on. Since parameter names are not in + * general available at runtime, without the annotation there would be + * no way of knowing which parameter corresponds to which property. + *

+ *

+ * If a constructor is annotated by the both {@code @java.beans.ConstructorProperties} + * and {@code @javax.management.ConstructorParameters} annotations + * the JMX introspection will give an absolute precedence to the latter one. + *

+ * + * @since 1.9 + */ +@Documented @Target(CONSTRUCTOR) @Retention(RUNTIME) +public @interface ConstructorParameters { + /** + *

The getter names.

+ * + * @return the getter names corresponding to the parameters in the + * annotated constructor. + */ + String[] value(); +} diff --git a/jdk/src/java.management/share/classes/javax/management/MXBean.java b/jdk/src/java.management/share/classes/javax/management/MXBean.java index 766e36feda6..8784a5fbaf8 100644 --- a/jdk/src/java.management/share/classes/javax/management/MXBean.java +++ b/jdk/src/java.management/share/classes/javax/management/MXBean.java @@ -153,7 +153,7 @@ public class MemoryUsage implements Serializable {
 public class MemoryUsage {
     // standard JavaBean conventions with getters
-    @ConstructorProperties({"init", "used", "committed", "max"})
+    @ConstructorParameters({"init", "used", "committed", "max"})
     public MemoryUsage(long init, long used,
                        long committed, long max) {...}
     long getInit() {...}
@@ -168,8 +168,8 @@ public class MemoryUsage {
     

The definitions are the same in the two cases, except that with the MXBean, MemoryUsage no longer needs to be marked Serializable (though it can be). On - the other hand, we have added a {@code @ConstructorProperties} annotation - to link the constructor parameters to the corresponding getters. + the other hand, we have added a {@link ConstructorParameters @ConstructorParameters} + annotation to link the constructor parameters to the corresponding getters. We will see more about this below.

MemoryUsage is a model-specific class. @@ -850,18 +850,24 @@ public interface ModuleMXBean { J.

  • Otherwise, if J has at least one public - constructor with a {@link java.beans.ConstructorProperties - ConstructorProperties} annotation, then one - of those constructors (not necessarily always the same one) - will be called to reconstruct an instance of J. + constructor with either {@link javax.management.ConstructorParameters + @javax.management.ConstructorParameters} or + {@code @java.beans.ConstructoProperties} annotation, then one of those + constructors (not necessarily always the same one) will be called to + reconstruct an instance of J. + If a constructor is annotated with both + {@code @javax.management.ConstructorParameters} and + {@code @java.beans.ConstructorProperties}, + {@code @javax.management.ConstructorParameters} will be used and + {@code @java.beans.ConstructorProperties} will be ignored. Every such annotation must list as many strings as the constructor has parameters; each string must name a property corresponding to a getter of J; and the type of this getter must be the same as the corresponding constructor parameter. It is not an error for there to be getters that - are not mentioned in the {@code ConstructorProperties} annotation - (these may correspond to information that is not needed to - reconstruct the object).

    + are not mentioned in the {@code @ConstructorParameters} or + {@code @ConstructorProperties} annotations (these may correspond to + information that is not needed to reconstruct the object).

    An instance of J is reconstructed by calling a constructor with the appropriate reconstructed items from the @@ -871,9 +877,10 @@ public interface ModuleMXBean { CompositeData} might come from an earlier version of J where not all the items were present. A constructor is applicable if all the properties named - in its {@code ConstructorProperties} annotation are present as items - in the {@code CompositeData}. If no constructor is - applicable, then the attempt to reconstruct J fails.

    + in its {@code @ConstructorParameters} or {@code @ConstructorProperties} + annotation are present as items in the {@code CompositeData}. + If no constructor is applicable, then the attempt to reconstruct + J fails.

    For any possible combination of properties, it must be the case that either (a) there are no applicable constructors, or @@ -909,8 +916,9 @@ public interface ModuleMXBean {

  • Otherwise, J is not reconstructible.

  • -

    Rule 2 is not applicable to subset Profiles of Java SE that do not - include the {@code java.beans} package. When targeting a runtime that does +

    When only {@code @java.beans.ConstructorProperties} is present then + rule 2 is not applicable to subset Profiles of Java SE that do not include + the {@code java.beans} package. When targeting a runtime that does not include the {@code java.beans} package, and where there is a mismatch between the compile-time and runtime environment whereby J is compiled with a public constructor and the {@code ConstructorProperties} @@ -957,14 +965,14 @@ public class NamedNumber { -

  • Public constructor with @ConstructorProperties annotation: +
  • Public constructor with @ConstructorParameters annotation:
     public class NamedNumber {
         public int getNumber() {return number;}
         public String getName() {return name;}
    -    @ConstructorProperties({"number", "name"})
    +    @ConstructorParameters({"number", "name"})
         public NamedNumber(int number, String name) {
             this.number = number;
             this.name = name;
    diff --git a/jdk/test/javax/management/Introspector/AnnotationSecurityTest.java b/jdk/test/javax/management/Introspector/AnnotationSecurityTest.java
    index 2d07a0a61bd..0afb509272c 100644
    --- a/jdk/test/javax/management/Introspector/AnnotationSecurityTest.java
    +++ b/jdk/test/javax/management/Introspector/AnnotationSecurityTest.java
    @@ -27,8 +27,7 @@
      * @summary Test that having a security manager doesn't trigger a
      *          NotCompliantMBeanException
      * @author Daniel Fuchs, Yves Joan
    - * @modules java.desktop
    - *          java.management
    + * @modules java.management
      * @run clean AnnotationSecurityTest Described UnDescribed DescribedMBean
      *            UnDescribedMBean SqeDescriptorKey DescribedMX DescribedMXBean
      * @run build AnnotationSecurityTest Described UnDescribed DescribedMBean
    @@ -40,13 +39,8 @@
     import java.io.File;
     import java.io.IOException;
     
    -import java.lang.annotation.Annotation;
     import java.lang.management.ManagementFactory;
    -import java.lang.reflect.AnnotatedElement;
     import java.lang.reflect.Method;
    -import java.lang.reflect.UndeclaredThrowableException;
    -
    -import javax.management.JMException;
     import javax.management.MBeanServer;
     import javax.management.ObjectName;
     /**
    diff --git a/jdk/test/javax/management/Introspector/Described.java b/jdk/test/javax/management/Introspector/Described.java
    index 1ef62efb54c..2b9d0684755 100644
    --- a/jdk/test/javax/management/Introspector/Described.java
    +++ b/jdk/test/javax/management/Introspector/Described.java
    @@ -25,7 +25,7 @@
      *
      * Used by AnnotationSecurityTest.java
      **/
    -import java.beans.ConstructorProperties;
    +import javax.management.ConstructorParameters;
     
     /**
      * An MBean used by AnnotationSecurityTest.java
    @@ -37,7 +37,7 @@ public class Described implements DescribedMBean {
         public Described() {}
     
         @SqeDescriptorKey("ONE PARAMETER CONSTRUCTOR Described")
    -    @ConstructorProperties({"name", "unused"})
    +    @ConstructorParameters({"name", "unused"})
         public Described(@SqeDescriptorKey("CONSTRUCTOR PARAMETER name")String name,
                 @SqeDescriptorKey("CONSTRUCTOR PARAMETER unused")String unused) {
             this.name = name ;
    diff --git a/jdk/test/javax/management/Introspector/DescribedMX.java b/jdk/test/javax/management/Introspector/DescribedMX.java
    index 625cc65f8af..b6e8c2652dc 100644
    --- a/jdk/test/javax/management/Introspector/DescribedMX.java
    +++ b/jdk/test/javax/management/Introspector/DescribedMX.java
    @@ -25,7 +25,7 @@
      *
      * Used by AnnotationSecurityTest.java
      **/
    -import java.beans.ConstructorProperties;
    +import javax.management.ConstructorParameters;
     
     /**
      * An MXBean used by AnnotationSecurityTest.java
    @@ -37,7 +37,7 @@ public class DescribedMX implements DescribedMXBean {
         public DescribedMX() {}
     
         @SqeDescriptorKey("ONE PARAMETER CONSTRUCTOR DescribedMX")
    -    @ConstructorProperties({"name", "unused"})
    +    @ConstructorParameters({"name", "unused"})
         public DescribedMX(@SqeDescriptorKey("CONSTRUCTOR PARAMETER name")String name,
                 @SqeDescriptorKey("CONSTRUCTOR PARAMETER unused")String unused) {
             this.name = name ;
    diff --git a/jdk/test/javax/management/Introspector/LegacyConstructorPropertiesTest.java b/jdk/test/javax/management/Introspector/LegacyConstructorPropertiesTest.java
    new file mode 100644
    index 00000000000..4848aad5473
    --- /dev/null
    +++ b/jdk/test/javax/management/Introspector/LegacyConstructorPropertiesTest.java
    @@ -0,0 +1,106 @@
    +
    +/*
    + * 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.beans.ConstructorProperties;
    +import javax.management.ConstructorParameters;
    +import javax.management.MBeanServer;
    +import javax.management.MBeanServerFactory;
    +import javax.management.ObjectName;
    +
    +/*
    + * @test
    + * @bug 7199353
    + * @summary Asserts that 'java.beans.ConstructorProperties' annotation is still
    + *          recognized and properly handled for custom types mapped to open types.
    + *          Also, makes sure that if the same constructor is annotated by both
    + *          j.b.ConstructorProperties and j.m.ConstructorProperties annotations
    + *          only j.m.ConstructorProperties annotation is considered.
    + * @author Jaroslav Bachorik
    + * @modules java.management
    + *          java.desktop
    + * @run main LegacyConstructorPropertiesTest
    + */
    +
    +public class LegacyConstructorPropertiesTest {
    +    public static class CustomType {
    +        private String name;
    +        private int value;
    +        @ConstructorProperties({"name", "value"})
    +        public CustomType(String name, int value) {
    +            this.name = name;
    +            this.value = value;
    +        }
    +
    +        // if @java.beans.ConstructorProperties would be used
    +        // the introspector would choke on this
    +        @ConstructorProperties("noname")
    +        @ConstructorParameters("name")
    +        public CustomType(String name) {
    +            this.name = name;
    +            this.value = -1;
    +        }
    +
    +        public String getName() {
    +            return name;
    +        }
    +
    +        public void setName(String name) {
    +            this.name = name;
    +        }
    +
    +        public int getValue() {
    +            return value;
    +        }
    +
    +        public void setValue(int value) {
    +            this.value = value;
    +        }
    +    }
    +
    +    public static interface CustomMXBean {
    +        public CustomType getProp();
    +        public void setProp(CustomType prop);
    +    }
    +
    +    public static final class Custom implements CustomMXBean {
    +        private CustomType prop;
    +
    +        @Override
    +        public CustomType getProp() {
    +            return prop;
    +        }
    +
    +        @Override
    +        public void setProp(CustomType prop) {
    +            this.prop = prop;
    +        }
    +    }
    +
    +    public static void main(String[] args) throws Exception {
    +        MBeanServer mbs = MBeanServerFactory.createMBeanServer();
    +        CustomMXBean mbean = new Custom();
    +
    +        mbs.registerMBean(mbean, ObjectName.getInstance("test:type=Custom"));
    +    }
    +}
    diff --git a/jdk/test/javax/management/mxbean/AmbiguousConstructorTest.java b/jdk/test/javax/management/mxbean/AmbiguousConstructorTest.java
    index 2b251f66d26..0766d1a8050 100644
    --- a/jdk/test/javax/management/mxbean/AmbiguousConstructorTest.java
    +++ b/jdk/test/javax/management/mxbean/AmbiguousConstructorTest.java
    @@ -26,15 +26,13 @@
      * @bug 6175517 6278707
      * @summary Test that ambiguous ConstructorProperties annotations are detected.
      * @author Eamonn McManus
    - * @modules java.desktop
    - *          java.management
    + * @modules java.management
      * @run clean AmbiguousConstructorTest
      * @run build AmbiguousConstructorTest
      * @run main AmbiguousConstructorTest
      */
     
    -import java.beans.ConstructorProperties;
    -import java.io.InvalidObjectException;
    +import javax.management.ConstructorParameters;
     import javax.management.*;
     
     public class AmbiguousConstructorTest {
    @@ -76,13 +74,13 @@ public class AmbiguousConstructorTest {
             public int getC() {return 0;}
             public long getD() {return 0;}
     
    -        @ConstructorProperties({"a", "b"})
    +        @ConstructorParameters({"a", "b"})
             public Unambiguous(byte a, short b) {}
     
    -        @ConstructorProperties({"b", "c"})
    +        @ConstructorParameters({"b", "c"})
             public Unambiguous(short b, int c) {}
     
    -        @ConstructorProperties({"a", "b", "c"})
    +        @ConstructorParameters({"a", "b", "c"})
             public Unambiguous(byte a, short b, int c) {}
         }
     
    @@ -92,13 +90,13 @@ public class AmbiguousConstructorTest {
             public int getC() {return 0;}
             public long getD() {return 0;}
     
    -        @ConstructorProperties({"a", "b"})
    +        @ConstructorParameters({"a", "b"})
             public Ambiguous(byte a, short b) {}
     
    -        @ConstructorProperties({"b", "c"})
    +        @ConstructorParameters({"b", "c"})
             public Ambiguous(short b, int c) {}
     
    -        @ConstructorProperties({"a", "b", "c", "d"})
    +        @ConstructorParameters({"a", "b", "c", "d"})
             public Ambiguous(byte a, short b, int c, long d) {}
         }
     
    diff --git a/jdk/test/javax/management/mxbean/ExceptionDiagnosisTest.java b/jdk/test/javax/management/mxbean/ExceptionDiagnosisTest.java
    index 89ca763cfea..16ece4db261 100644
    --- a/jdk/test/javax/management/mxbean/ExceptionDiagnosisTest.java
    +++ b/jdk/test/javax/management/mxbean/ExceptionDiagnosisTest.java
    @@ -26,11 +26,10 @@
      * @bug 6713777
      * @summary Test that exception messages include all relevant information
      * @author Eamonn McManus
    - * @modules java.desktop
    - *          java.management
    + * @modules java.management
      */
     
    -import java.beans.ConstructorProperties;
    +import javax.management.ConstructorParameters;
     import java.io.File;
     import java.lang.reflect.InvocationTargetException;
     import java.lang.reflect.Method;
    @@ -131,7 +130,7 @@ public class ExceptionDiagnosisTest {
         }
     
         public static class CaseProb {
    -        @ConstructorProperties({"urlPath"})
    +        @ConstructorParameters({"urlPath"})
             public CaseProb(String urlPath) {}
     
             public String getURLPath() {return null;}
    diff --git a/jdk/test/javax/management/mxbean/LeakTest.java b/jdk/test/javax/management/mxbean/LeakTest.java
    index 982ec225d4b..43ac996ab5e 100644
    --- a/jdk/test/javax/management/mxbean/LeakTest.java
    +++ b/jdk/test/javax/management/mxbean/LeakTest.java
    @@ -25,8 +25,7 @@
      * @bug 6482247
      * @summary Test that creating MXBeans does not introduce memory leaks.
      * @author Eamonn McManus
    - * @modules java.desktop
    - *          java.management
    + * @modules java.management
      * @run build LeakTest RandomMXBeanTest MerlinMXBean TigerMXBean
      * @run main LeakTest
      */
    diff --git a/jdk/test/javax/management/mxbean/MXBeanTest.java b/jdk/test/javax/management/mxbean/MXBeanTest.java
    index 9017d497a0d..6123be2365e 100644
    --- a/jdk/test/javax/management/mxbean/MXBeanTest.java
    +++ b/jdk/test/javax/management/mxbean/MXBeanTest.java
    @@ -27,8 +27,7 @@
      * @summary General MXBean test.
      * @author Eamonn McManus
      * @author Jaroslav Bachorik
    - * @modules java.desktop
    - *          java.management
    + * @modules java.management
      * @run clean MXBeanTest MerlinMXBean TigerMXBean
      * @run build MXBeanTest MerlinMXBean TigerMXBean
      * @run main MXBeanTest
    diff --git a/jdk/test/javax/management/mxbean/PropertyNamesTest.java b/jdk/test/javax/management/mxbean/PropertyNamesTest.java
    index d8f6845ffd2..534f76c11d9 100644
    --- a/jdk/test/javax/management/mxbean/PropertyNamesTest.java
    +++ b/jdk/test/javax/management/mxbean/PropertyNamesTest.java
    @@ -26,14 +26,13 @@
      * @bug 6175517
      * @summary Test the PropertyNames annotation with MXBeans
      * @author Eamonn McManus
    - * @modules java.desktop
    - *          java.management
    + * @modules java.management
      * @run clean PropertyNamesTest
      * @run build PropertyNamesTest
      * @run main PropertyNamesTest
      */
     
    -import java.beans.ConstructorProperties;
    +import javax.management.ConstructorParameters;
     import java.util.Collections;
     import java.util.List;
     import javax.management.JMX;
    @@ -95,7 +94,7 @@ public class PropertyNamesTest {
         }
     
         public static class Point {
    -        @ConstructorProperties({"x", "y"})
    +        @ConstructorParameters({"x", "y"})
             public Point(int x, int y) {
                 this.x = x;
                 this.y = y;
    @@ -123,17 +122,17 @@ public class PropertyNamesTest {
         }
     
         public static class Evolve {
    -        @ConstructorProperties({"oldInt"})
    +        @ConstructorParameters({"oldInt"})
             public Evolve(int oldInt) {
                 this(oldInt, "defaultString");
             }
     
    -        @ConstructorProperties({"oldInt", "newString"})
    +        @ConstructorParameters({"oldInt", "newString"})
             public Evolve(int oldInt, String newString) {
                 this(oldInt, newString, Collections.emptyList());
             }
     
    -        @ConstructorProperties({"oldInt", "newString", "newerList"})
    +        @ConstructorParameters({"oldInt", "newString", "newerList"})
             public Evolve(int oldInt, String newString, List newerList) {
                 this.oldInt = oldInt;
                 this.newString = newString;
    diff --git a/jdk/test/javax/management/mxbean/TigerMXBean.java b/jdk/test/javax/management/mxbean/TigerMXBean.java
    index cfc47a90b2c..e4129b77806 100644
    --- a/jdk/test/javax/management/mxbean/TigerMXBean.java
    +++ b/jdk/test/javax/management/mxbean/TigerMXBean.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 2005, 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
    @@ -21,7 +21,7 @@
      * questions.
      */
     
    -import java.beans.ConstructorProperties;
    +import javax.management.ConstructorParameters;
     import java.util.Arrays;
     import java.util.Collections;
     import java.util.HashSet;
    @@ -42,7 +42,7 @@ import javax.management.openmbean.TabularType;
     public interface TigerMXBean {
     
         class Point {
    -        @ConstructorProperties({"x", "y"})
    +        @ConstructorParameters({"x", "y"})
             public Point(double x, double y) {
                 this.x = x;
                 this.y = y;
    
    From 3d2b56d9b3a57c107edadacef59e650fbd725220 Mon Sep 17 00:00:00 2001
    From: Martin Doerr 
    Date: Fri, 9 Oct 2015 20:58:25 +0200
    Subject: [PATCH 07/75] 8138890: C1: Ambiguous operator delete
    
    XlC on AIX rejects to compile LIRGenerator and RangeCheckEliminator::Verification
    
    Reviewed-by: simonis, goetz, twisti
    ---
     hotspot/src/share/vm/c1/c1_LIRGenerator.hpp          | 7 ++++++-
     hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp | 8 +++++++-
     2 files changed, 13 insertions(+), 2 deletions(-)
    
    diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp
    index 1009235d4dc..42051a307c1 100644
    --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp
    +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp
    @@ -153,8 +153,13 @@ class PhiResolver: public CompilationResourceObj {
     
     // only the classes below belong in the same file
     class LIRGenerator: public InstructionVisitor, public BlockClosure {
    -
    + // LIRGenerator should never get instatiated on the heap.
      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);
    +
       Compilation*  _compilation;
       ciMethod*     _method;    // method that we are compiling
       PhiResolverState  _resolver_state;
    diff --git a/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp b/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp
    index 2fd6cb59221..608f39a9196 100644
    --- a/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp
    +++ b/hotspot/src/share/vm/c1/c1_RangeCheckElimination.hpp
    @@ -45,8 +45,14 @@ private:
       define_stack(IntegerStack, intArray)
       define_array(IntegerMap, IntegerStack*)
     
    -  class Verification : public _ValueObj /*VALUE_OBJ_CLASS_SPEC*/, public BlockClosure {
    +  class Verification : public BlockClosure {
    +  // RangeCheckEliminator::Verification should never get instatiated on the heap.
       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);
    +
         IR *_ir;
         boolArray _used;
         BlockBeginList _current;
    
    From 096fa934a8aa19c9240d4cb41a7907bd44c50909 Mon Sep 17 00:00:00 2001
    From: Roland Westrelin 
    Date: Fri, 16 Oct 2015 16:53:02 +0200
    Subject: [PATCH 08/75] 8136473: failed: no mismatched stores, except on raw
     memory: StoreB StoreI
    
    Mismatched stores on same slice possible with Unsafe.Put*Unaligned methods
    
    Reviewed-by: kvn, thartmann
    ---
     hotspot/src/share/vm/opto/graphKit.cpp        |  32 +++-
     hotspot/src/share/vm/opto/graphKit.hpp        |  32 ++--
     hotspot/src/share/vm/opto/idealKit.cpp        |   6 +-
     hotspot/src/share/vm/opto/idealKit.hpp        |   4 +-
     hotspot/src/share/vm/opto/library_call.cpp    | 153 ++++++++++--------
     hotspot/src/share/vm/opto/memnode.cpp         |  15 +-
     hotspot/src/share/vm/opto/memnode.hpp         |  16 +-
     ...TestUnsafeUnalignedMismatchedAccesses.java | 122 ++++++++++++++
     8 files changed, 288 insertions(+), 92 deletions(-)
     create mode 100644 hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.java
    
    diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp
    index 3ccdcf6dbe3..2683f477be6 100644
    --- a/hotspot/src/share/vm/opto/graphKit.cpp
    +++ b/hotspot/src/share/vm/opto/graphKit.cpp
    @@ -1457,7 +1457,11 @@ void GraphKit::set_all_memory_call(Node* call, bool separate_io_proj) {
     // factory methods in "int adr_idx"
     Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt,
                               int adr_idx,
    -                          MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency, bool require_atomic_access) {
    +                          MemNode::MemOrd mo,
    +                          LoadNode::ControlDependency control_dependency,
    +                          bool require_atomic_access,
    +                          bool unaligned,
    +                          bool mismatched) {
       assert(adr_idx != Compile::AliasIdxTop, "use other make_load factory" );
       const TypePtr* adr_type = NULL; // debug-mode-only argument
       debug_only(adr_type = C->get_adr_type(adr_idx));
    @@ -1470,6 +1474,12 @@ Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt,
       } else {
         ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency);
       }
    +  if (unaligned) {
    +    ld->as_Load()->set_unaligned_access();
    +  }
    +  if (mismatched) {
    +    ld->as_Load()->set_mismatched_access();
    +  }
       ld = _gvn.transform(ld);
       if ((bt == T_OBJECT) && C->do_escape_analysis() || C->eliminate_boxing()) {
         // Improve graph before escape analysis and boxing elimination.
    @@ -1481,7 +1491,9 @@ Node* GraphKit::make_load(Node* ctl, Node* adr, const Type* t, BasicType bt,
     Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt,
                                     int adr_idx,
                                     MemNode::MemOrd mo,
    -                                bool require_atomic_access) {
    +                                bool require_atomic_access,
    +                                bool unaligned,
    +                                bool mismatched) {
       assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory" );
       const TypePtr* adr_type = NULL;
       debug_only(adr_type = C->get_adr_type(adr_idx));
    @@ -1494,6 +1506,12 @@ Node* GraphKit::store_to_memory(Node* ctl, Node* adr, Node *val, BasicType bt,
       } else {
         st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt, mo);
       }
    +  if (unaligned) {
    +    st->as_Store()->set_unaligned_access();
    +  }
    +  if (mismatched) {
    +    st->as_Store()->set_mismatched_access();
    +  }
       st = _gvn.transform(st);
       set_memory(st, adr_idx);
       // Back-to-back stores can only remove intermediate store with DU info
    @@ -1587,7 +1605,8 @@ Node* GraphKit::store_oop(Node* ctl,
                               const TypeOopPtr* val_type,
                               BasicType bt,
                               bool use_precise,
    -                          MemNode::MemOrd mo) {
    +                          MemNode::MemOrd mo,
    +                          bool mismatched) {
       // Transformation of a value which could be NULL pointer (CastPP #NULL)
       // could be delayed during Parse (for example, in adjust_map_after_if()).
       // Execute transformation here to avoid barrier generation in such case.
    @@ -1607,7 +1626,7 @@ Node* GraphKit::store_oop(Node* ctl,
                   NULL /* pre_val */,
                   bt);
     
    -  Node* store = store_to_memory(control(), adr, val, bt, adr_idx, mo);
    +  Node* store = store_to_memory(control(), adr, val, bt, adr_idx, mo, mismatched);
       post_barrier(control(), store, obj, adr, adr_idx, val, bt, use_precise);
       return store;
     }
    @@ -1619,7 +1638,8 @@ Node* GraphKit::store_oop_to_unknown(Node* ctl,
                                  const TypePtr* adr_type,
                                  Node* val,
                                  BasicType bt,
    -                             MemNode::MemOrd mo) {
    +                             MemNode::MemOrd mo,
    +                             bool mismatched) {
       Compile::AliasType* at = C->alias_type(adr_type);
       const TypeOopPtr* val_type = NULL;
       if (adr_type->isa_instptr()) {
    @@ -1638,7 +1658,7 @@ Node* GraphKit::store_oop_to_unknown(Node* ctl,
       if (val_type == NULL) {
         val_type = TypeInstPtr::BOTTOM;
       }
    -  return store_oop(ctl, obj, adr, adr_type, val, val_type, bt, true, mo);
    +  return store_oop(ctl, obj, adr, adr_type, val, val_type, bt, true, mo, mismatched);
     }
     
     
    diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp
    index 24dbba08a11..0e10afa0ff5 100644
    --- a/hotspot/src/share/vm/opto/graphKit.hpp
    +++ b/hotspot/src/share/vm/opto/graphKit.hpp
    @@ -513,23 +513,28 @@ class GraphKit : public Phase {
       // of volatile fields.
       Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt,
                       MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest,
    -                  bool require_atomic_access = false) {
    +                  bool require_atomic_access = false, bool unaligned = false,
    +                  bool mismatched = false) {
         // This version computes alias_index from bottom_type
         return make_load(ctl, adr, t, bt, adr->bottom_type()->is_ptr(),
    -                     mo, control_dependency, require_atomic_access);
    +                     mo, control_dependency, require_atomic_access,
    +                     unaligned, mismatched);
       }
       Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, const TypePtr* adr_type,
                       MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest,
    -                  bool require_atomic_access = false) {
    +                  bool require_atomic_access = false, bool unaligned = false,
    +                  bool mismatched = false) {
         // This version computes alias_index from an address type
         assert(adr_type != NULL, "use other make_load factory");
         return make_load(ctl, adr, t, bt, C->get_alias_index(adr_type),
    -                     mo, control_dependency, require_atomic_access);
    +                     mo, control_dependency, require_atomic_access,
    +                     unaligned, mismatched);
       }
       // This is the base version which is given an alias index.
       Node* make_load(Node* ctl, Node* adr, const Type* t, BasicType bt, int adr_idx,
                       MemNode::MemOrd mo, LoadNode::ControlDependency control_dependency = LoadNode::DependsOnlyOnTest,
    -                  bool require_atomic_access = false);
    +                  bool require_atomic_access = false, bool unaligned = false,
    +                  bool mismatched = false);
     
       // Create & transform a StoreNode and store the effect into the
       // parser's memory state.
    @@ -542,19 +547,24 @@ class GraphKit : public Phase {
       Node* store_to_memory(Node* ctl, Node* adr, Node* val, BasicType bt,
                             const TypePtr* adr_type,
                             MemNode::MemOrd mo,
    -                        bool require_atomic_access = false) {
    +                        bool require_atomic_access = false,
    +                        bool unaligned = false,
    +                        bool mismatched = false) {
         // This version computes alias_index from an address type
         assert(adr_type != NULL, "use other store_to_memory factory");
         return store_to_memory(ctl, adr, val, bt,
                                C->get_alias_index(adr_type),
    -                           mo, require_atomic_access);
    +                           mo, require_atomic_access,
    +                           unaligned, mismatched);
       }
       // This is the base version which is given alias index
       // Return the new StoreXNode
       Node* store_to_memory(Node* ctl, Node* adr, Node* val, BasicType bt,
                             int adr_idx,
                             MemNode::MemOrd,
    -                        bool require_atomic_access = false);
    +                        bool require_atomic_access = false,
    +                        bool unaligned = false,
    +                        bool mismatched = false);
     
     
       // All in one pre-barrier, store, post_barrier
    @@ -577,7 +587,8 @@ class GraphKit : public Phase {
                       const TypeOopPtr* val_type,
                       BasicType bt,
                       bool use_precise,
    -                  MemNode::MemOrd mo);
    +                  MemNode::MemOrd mo,
    +                  bool mismatched = false);
     
       Node* store_oop_to_object(Node* ctl,
                                 Node* obj,   // containing obj
    @@ -608,7 +619,8 @@ class GraphKit : public Phase {
                                  const TypePtr* adr_type,
                                  Node* val,
                                  BasicType bt,
    -                             MemNode::MemOrd mo);
    +                             MemNode::MemOrd mo,
    +                             bool mismatched = false);
     
       // For the few case where the barriers need special help
       void pre_barrier(bool do_load, Node* ctl,
    diff --git a/hotspot/src/share/vm/opto/idealKit.cpp b/hotspot/src/share/vm/opto/idealKit.cpp
    index 3038982e648..0dd58c850a9 100644
    --- a/hotspot/src/share/vm/opto/idealKit.cpp
    +++ b/hotspot/src/share/vm/opto/idealKit.cpp
    @@ -368,7 +368,8 @@ Node* IdealKit::load(Node* ctl,
     
     Node* IdealKit::store(Node* ctl, Node* adr, Node *val, BasicType bt,
                           int adr_idx,
    -                      MemNode::MemOrd mo, bool require_atomic_access) {
    +                      MemNode::MemOrd mo, bool require_atomic_access,
    +                      bool mismatched) {
       assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory");
       const TypePtr* adr_type = NULL;
       debug_only(adr_type = C->get_adr_type(adr_idx));
    @@ -379,6 +380,9 @@ Node* IdealKit::store(Node* ctl, Node* adr, Node *val, BasicType bt,
       } else {
         st = StoreNode::make(_gvn, ctl, mem, adr, adr_type, val, bt, mo);
       }
    +  if (mismatched) {
    +    st->as_Store()->set_mismatched_access();
    +  }
       st = transform(st);
       set_memory(st, adr_idx);
     
    diff --git a/hotspot/src/share/vm/opto/idealKit.hpp b/hotspot/src/share/vm/opto/idealKit.hpp
    index 3828d30cc0b..f99f2792c95 100644
    --- a/hotspot/src/share/vm/opto/idealKit.hpp
    +++ b/hotspot/src/share/vm/opto/idealKit.hpp
    @@ -228,7 +228,9 @@ class IdealKit: public StackObj {
                   BasicType bt,
                   int adr_idx,
                   MemNode::MemOrd mo,
    -              bool require_atomic_access = false);
    +              bool require_atomic_access = false,
    +              bool mismatched = false
    +              );
     
       // Store a card mark ordered after store_oop
       Node* storeCM(Node* ctl,
    diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp
    index 2c4b22423b7..e62b66e8d89 100644
    --- a/hotspot/src/share/vm/opto/library_call.cpp
    +++ b/hotspot/src/share/vm/opto/library_call.cpp
    @@ -234,7 +234,7 @@ class LibraryCallKit : public GraphKit {
       // Generates the guards that check whether the result of
       // Unsafe.getObject should be recorded in an SATB log buffer.
       void insert_pre_barrier(Node* base_oop, Node* offset, Node* pre_val, bool need_mem_bar);
    -  bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile);
    +  bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool is_unaligned);
       static bool klass_needs_init_guard(Node* kls);
       bool inline_unsafe_allocate();
       bool inline_unsafe_copyMemory();
    @@ -515,72 +515,72 @@ bool LibraryCallKit::try_to_inline(int predicate) {
       case vmIntrinsics::_indexOf:                  return inline_string_indexOf();
       case vmIntrinsics::_equals:                   return inline_string_equals();
     
    -  case vmIntrinsics::_getObject:                return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT,  !is_volatile);
    -  case vmIntrinsics::_getBoolean:               return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, !is_volatile);
    -  case vmIntrinsics::_getByte:                  return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE,    !is_volatile);
    -  case vmIntrinsics::_getShort:                 return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT,   !is_volatile);
    -  case vmIntrinsics::_getChar:                  return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR,    !is_volatile);
    -  case vmIntrinsics::_getInt:                   return inline_unsafe_access(!is_native_ptr, !is_store, T_INT,     !is_volatile);
    -  case vmIntrinsics::_getLong:                  return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG,    !is_volatile);
    -  case vmIntrinsics::_getFloat:                 return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT,   !is_volatile);
    -  case vmIntrinsics::_getDouble:                return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE,  !is_volatile);
    -  case vmIntrinsics::_putObject:                return inline_unsafe_access(!is_native_ptr,  is_store, T_OBJECT,  !is_volatile);
    -  case vmIntrinsics::_putBoolean:               return inline_unsafe_access(!is_native_ptr,  is_store, T_BOOLEAN, !is_volatile);
    -  case vmIntrinsics::_putByte:                  return inline_unsafe_access(!is_native_ptr,  is_store, T_BYTE,    !is_volatile);
    -  case vmIntrinsics::_putShort:                 return inline_unsafe_access(!is_native_ptr,  is_store, T_SHORT,   !is_volatile);
    -  case vmIntrinsics::_putChar:                  return inline_unsafe_access(!is_native_ptr,  is_store, T_CHAR,    !is_volatile);
    -  case vmIntrinsics::_putInt:                   return inline_unsafe_access(!is_native_ptr,  is_store, T_INT,     !is_volatile);
    -  case vmIntrinsics::_putLong:                  return inline_unsafe_access(!is_native_ptr,  is_store, T_LONG,    !is_volatile);
    -  case vmIntrinsics::_putFloat:                 return inline_unsafe_access(!is_native_ptr,  is_store, T_FLOAT,   !is_volatile);
    -  case vmIntrinsics::_putDouble:                return inline_unsafe_access(!is_native_ptr,  is_store, T_DOUBLE,  !is_volatile);
    +  case vmIntrinsics::_getObject:                return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT,  !is_volatile, false);
    +  case vmIntrinsics::_getBoolean:               return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, !is_volatile, false);
    +  case vmIntrinsics::_getByte:                  return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE,    !is_volatile, false);
    +  case vmIntrinsics::_getShort:                 return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT,   !is_volatile, false);
    +  case vmIntrinsics::_getChar:                  return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR,    !is_volatile, false);
    +  case vmIntrinsics::_getInt:                   return inline_unsafe_access(!is_native_ptr, !is_store, T_INT,     !is_volatile, false);
    +  case vmIntrinsics::_getLong:                  return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG,    !is_volatile, false);
    +  case vmIntrinsics::_getFloat:                 return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT,   !is_volatile, false);
    +  case vmIntrinsics::_getDouble:                return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE,  !is_volatile, false);
    +  case vmIntrinsics::_putObject:                return inline_unsafe_access(!is_native_ptr,  is_store, T_OBJECT,  !is_volatile, false);
    +  case vmIntrinsics::_putBoolean:               return inline_unsafe_access(!is_native_ptr,  is_store, T_BOOLEAN, !is_volatile, false);
    +  case vmIntrinsics::_putByte:                  return inline_unsafe_access(!is_native_ptr,  is_store, T_BYTE,    !is_volatile, false);
    +  case vmIntrinsics::_putShort:                 return inline_unsafe_access(!is_native_ptr,  is_store, T_SHORT,   !is_volatile, false);
    +  case vmIntrinsics::_putChar:                  return inline_unsafe_access(!is_native_ptr,  is_store, T_CHAR,    !is_volatile, false);
    +  case vmIntrinsics::_putInt:                   return inline_unsafe_access(!is_native_ptr,  is_store, T_INT,     !is_volatile, false);
    +  case vmIntrinsics::_putLong:                  return inline_unsafe_access(!is_native_ptr,  is_store, T_LONG,    !is_volatile, false);
    +  case vmIntrinsics::_putFloat:                 return inline_unsafe_access(!is_native_ptr,  is_store, T_FLOAT,   !is_volatile, false);
    +  case vmIntrinsics::_putDouble:                return inline_unsafe_access(!is_native_ptr,  is_store, T_DOUBLE,  !is_volatile, false);
     
    -  case vmIntrinsics::_getByte_raw:              return inline_unsafe_access( is_native_ptr, !is_store, T_BYTE,    !is_volatile);
    -  case vmIntrinsics::_getShort_raw:             return inline_unsafe_access( is_native_ptr, !is_store, T_SHORT,   !is_volatile);
    -  case vmIntrinsics::_getChar_raw:              return inline_unsafe_access( is_native_ptr, !is_store, T_CHAR,    !is_volatile);
    -  case vmIntrinsics::_getInt_raw:               return inline_unsafe_access( is_native_ptr, !is_store, T_INT,     !is_volatile);
    -  case vmIntrinsics::_getLong_raw:              return inline_unsafe_access( is_native_ptr, !is_store, T_LONG,    !is_volatile);
    -  case vmIntrinsics::_getFloat_raw:             return inline_unsafe_access( is_native_ptr, !is_store, T_FLOAT,   !is_volatile);
    -  case vmIntrinsics::_getDouble_raw:            return inline_unsafe_access( is_native_ptr, !is_store, T_DOUBLE,  !is_volatile);
    -  case vmIntrinsics::_getAddress_raw:           return inline_unsafe_access( is_native_ptr, !is_store, T_ADDRESS, !is_volatile);
    +  case vmIntrinsics::_getByte_raw:              return inline_unsafe_access( is_native_ptr, !is_store, T_BYTE,    !is_volatile, false);
    +  case vmIntrinsics::_getShort_raw:             return inline_unsafe_access( is_native_ptr, !is_store, T_SHORT,   !is_volatile, false);
    +  case vmIntrinsics::_getChar_raw:              return inline_unsafe_access( is_native_ptr, !is_store, T_CHAR,    !is_volatile, false);
    +  case vmIntrinsics::_getInt_raw:               return inline_unsafe_access( is_native_ptr, !is_store, T_INT,     !is_volatile, false);
    +  case vmIntrinsics::_getLong_raw:              return inline_unsafe_access( is_native_ptr, !is_store, T_LONG,    !is_volatile, false);
    +  case vmIntrinsics::_getFloat_raw:             return inline_unsafe_access( is_native_ptr, !is_store, T_FLOAT,   !is_volatile, false);
    +  case vmIntrinsics::_getDouble_raw:            return inline_unsafe_access( is_native_ptr, !is_store, T_DOUBLE,  !is_volatile, false);
    +  case vmIntrinsics::_getAddress_raw:           return inline_unsafe_access( is_native_ptr, !is_store, T_ADDRESS, !is_volatile, false);
     
    -  case vmIntrinsics::_putByte_raw:              return inline_unsafe_access( is_native_ptr,  is_store, T_BYTE,    !is_volatile);
    -  case vmIntrinsics::_putShort_raw:             return inline_unsafe_access( is_native_ptr,  is_store, T_SHORT,   !is_volatile);
    -  case vmIntrinsics::_putChar_raw:              return inline_unsafe_access( is_native_ptr,  is_store, T_CHAR,    !is_volatile);
    -  case vmIntrinsics::_putInt_raw:               return inline_unsafe_access( is_native_ptr,  is_store, T_INT,     !is_volatile);
    -  case vmIntrinsics::_putLong_raw:              return inline_unsafe_access( is_native_ptr,  is_store, T_LONG,    !is_volatile);
    -  case vmIntrinsics::_putFloat_raw:             return inline_unsafe_access( is_native_ptr,  is_store, T_FLOAT,   !is_volatile);
    -  case vmIntrinsics::_putDouble_raw:            return inline_unsafe_access( is_native_ptr,  is_store, T_DOUBLE,  !is_volatile);
    -  case vmIntrinsics::_putAddress_raw:           return inline_unsafe_access( is_native_ptr,  is_store, T_ADDRESS, !is_volatile);
    +  case vmIntrinsics::_putByte_raw:              return inline_unsafe_access( is_native_ptr,  is_store, T_BYTE,    !is_volatile, false);
    +  case vmIntrinsics::_putShort_raw:             return inline_unsafe_access( is_native_ptr,  is_store, T_SHORT,   !is_volatile, false);
    +  case vmIntrinsics::_putChar_raw:              return inline_unsafe_access( is_native_ptr,  is_store, T_CHAR,    !is_volatile, false);
    +  case vmIntrinsics::_putInt_raw:               return inline_unsafe_access( is_native_ptr,  is_store, T_INT,     !is_volatile, false);
    +  case vmIntrinsics::_putLong_raw:              return inline_unsafe_access( is_native_ptr,  is_store, T_LONG,    !is_volatile, false);
    +  case vmIntrinsics::_putFloat_raw:             return inline_unsafe_access( is_native_ptr,  is_store, T_FLOAT,   !is_volatile, false);
    +  case vmIntrinsics::_putDouble_raw:            return inline_unsafe_access( is_native_ptr,  is_store, T_DOUBLE,  !is_volatile, false);
    +  case vmIntrinsics::_putAddress_raw:           return inline_unsafe_access( is_native_ptr,  is_store, T_ADDRESS, !is_volatile, false);
     
    -  case vmIntrinsics::_getObjectVolatile:        return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT,   is_volatile);
    -  case vmIntrinsics::_getBooleanVolatile:       return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN,  is_volatile);
    -  case vmIntrinsics::_getByteVolatile:          return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE,     is_volatile);
    -  case vmIntrinsics::_getShortVolatile:         return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT,    is_volatile);
    -  case vmIntrinsics::_getCharVolatile:          return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR,     is_volatile);
    -  case vmIntrinsics::_getIntVolatile:           return inline_unsafe_access(!is_native_ptr, !is_store, T_INT,      is_volatile);
    -  case vmIntrinsics::_getLongVolatile:          return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG,     is_volatile);
    -  case vmIntrinsics::_getFloatVolatile:         return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT,    is_volatile);
    -  case vmIntrinsics::_getDoubleVolatile:        return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE,   is_volatile);
    +  case vmIntrinsics::_getObjectVolatile:        return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT,   is_volatile, false);
    +  case vmIntrinsics::_getBooleanVolatile:       return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN,  is_volatile, false);
    +  case vmIntrinsics::_getByteVolatile:          return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE,     is_volatile, false);
    +  case vmIntrinsics::_getShortVolatile:         return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT,    is_volatile, false);
    +  case vmIntrinsics::_getCharVolatile:          return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR,     is_volatile, false);
    +  case vmIntrinsics::_getIntVolatile:           return inline_unsafe_access(!is_native_ptr, !is_store, T_INT,      is_volatile, false);
    +  case vmIntrinsics::_getLongVolatile:          return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG,     is_volatile, false);
    +  case vmIntrinsics::_getFloatVolatile:         return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT,    is_volatile, false);
    +  case vmIntrinsics::_getDoubleVolatile:        return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE,   is_volatile, false);
     
    -  case vmIntrinsics::_putObjectVolatile:        return inline_unsafe_access(!is_native_ptr,  is_store, T_OBJECT,   is_volatile);
    -  case vmIntrinsics::_putBooleanVolatile:       return inline_unsafe_access(!is_native_ptr,  is_store, T_BOOLEAN,  is_volatile);
    -  case vmIntrinsics::_putByteVolatile:          return inline_unsafe_access(!is_native_ptr,  is_store, T_BYTE,     is_volatile);
    -  case vmIntrinsics::_putShortVolatile:         return inline_unsafe_access(!is_native_ptr,  is_store, T_SHORT,    is_volatile);
    -  case vmIntrinsics::_putCharVolatile:          return inline_unsafe_access(!is_native_ptr,  is_store, T_CHAR,     is_volatile);
    -  case vmIntrinsics::_putIntVolatile:           return inline_unsafe_access(!is_native_ptr,  is_store, T_INT,      is_volatile);
    -  case vmIntrinsics::_putLongVolatile:          return inline_unsafe_access(!is_native_ptr,  is_store, T_LONG,     is_volatile);
    -  case vmIntrinsics::_putFloatVolatile:         return inline_unsafe_access(!is_native_ptr,  is_store, T_FLOAT,    is_volatile);
    -  case vmIntrinsics::_putDoubleVolatile:        return inline_unsafe_access(!is_native_ptr,  is_store, T_DOUBLE,   is_volatile);
    +  case vmIntrinsics::_putObjectVolatile:        return inline_unsafe_access(!is_native_ptr,  is_store, T_OBJECT,   is_volatile, false);
    +  case vmIntrinsics::_putBooleanVolatile:       return inline_unsafe_access(!is_native_ptr,  is_store, T_BOOLEAN,  is_volatile, false);
    +  case vmIntrinsics::_putByteVolatile:          return inline_unsafe_access(!is_native_ptr,  is_store, T_BYTE,     is_volatile, false);
    +  case vmIntrinsics::_putShortVolatile:         return inline_unsafe_access(!is_native_ptr,  is_store, T_SHORT,    is_volatile, false);
    +  case vmIntrinsics::_putCharVolatile:          return inline_unsafe_access(!is_native_ptr,  is_store, T_CHAR,     is_volatile, false);
    +  case vmIntrinsics::_putIntVolatile:           return inline_unsafe_access(!is_native_ptr,  is_store, T_INT,      is_volatile, false);
    +  case vmIntrinsics::_putLongVolatile:          return inline_unsafe_access(!is_native_ptr,  is_store, T_LONG,     is_volatile, false);
    +  case vmIntrinsics::_putFloatVolatile:         return inline_unsafe_access(!is_native_ptr,  is_store, T_FLOAT,    is_volatile, false);
    +  case vmIntrinsics::_putDoubleVolatile:        return inline_unsafe_access(!is_native_ptr,  is_store, T_DOUBLE,   is_volatile, false);
     
    -  case vmIntrinsics::_getShortUnaligned:        return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT,   !is_volatile);
    -  case vmIntrinsics::_getCharUnaligned:         return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR,    !is_volatile);
    -  case vmIntrinsics::_getIntUnaligned:          return inline_unsafe_access(!is_native_ptr, !is_store, T_INT,     !is_volatile);
    -  case vmIntrinsics::_getLongUnaligned:         return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG,    !is_volatile);
    +  case vmIntrinsics::_getShortUnaligned:        return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT,   !is_volatile, true);
    +  case vmIntrinsics::_getCharUnaligned:         return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR,    !is_volatile, true);
    +  case vmIntrinsics::_getIntUnaligned:          return inline_unsafe_access(!is_native_ptr, !is_store, T_INT,     !is_volatile, true);
    +  case vmIntrinsics::_getLongUnaligned:         return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG,    !is_volatile, true);
     
    -  case vmIntrinsics::_putShortUnaligned:        return inline_unsafe_access(!is_native_ptr,  is_store, T_SHORT,   !is_volatile);
    -  case vmIntrinsics::_putCharUnaligned:         return inline_unsafe_access(!is_native_ptr,  is_store, T_CHAR,    !is_volatile);
    -  case vmIntrinsics::_putIntUnaligned:          return inline_unsafe_access(!is_native_ptr,  is_store, T_INT,     !is_volatile);
    -  case vmIntrinsics::_putLongUnaligned:         return inline_unsafe_access(!is_native_ptr,  is_store, T_LONG,    !is_volatile);
    +  case vmIntrinsics::_putShortUnaligned:        return inline_unsafe_access(!is_native_ptr,  is_store, T_SHORT,   !is_volatile, true);
    +  case vmIntrinsics::_putCharUnaligned:         return inline_unsafe_access(!is_native_ptr,  is_store, T_CHAR,    !is_volatile, true);
    +  case vmIntrinsics::_putIntUnaligned:          return inline_unsafe_access(!is_native_ptr,  is_store, T_INT,     !is_volatile, true);
    +  case vmIntrinsics::_putLongUnaligned:         return inline_unsafe_access(!is_native_ptr,  is_store, T_LONG,    !is_volatile, true);
     
       case vmIntrinsics::_compareAndSwapObject:     return inline_unsafe_load_store(T_OBJECT, LS_cmpxchg);
       case vmIntrinsics::_compareAndSwapInt:        return inline_unsafe_load_store(T_INT,    LS_cmpxchg);
    @@ -2272,7 +2272,7 @@ const TypeOopPtr* LibraryCallKit::sharpen_unsafe_type(Compile::AliasType* alias_
       return NULL;
     }
     
    -bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile) {
    +bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool unaligned) {
       if (callee()->is_static())  return false;  // caller must have the capability!
     
     #ifndef PRODUCT
    @@ -2414,7 +2414,24 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas
       // of safe & unsafe memory.
       if (need_mem_bar) insert_mem_bar(Op_MemBarCPUOrder);
     
    -   if (!is_store) {
    +  assert(is_native_ptr || alias_type->adr_type() == TypeOopPtr::BOTTOM ||
    +         alias_type->field() != NULL || alias_type->element() != NULL, "field, array element or unknown");
    +  bool mismatched = false;
    +  if (alias_type->element() != NULL || alias_type->field() != NULL) {
    +    BasicType bt;
    +    if (alias_type->element() != NULL) {
    +      const Type* element = alias_type->element();
    +      bt = element->isa_narrowoop() ? T_OBJECT : element->array_element_basic_type();
    +    } else {
    +      bt = alias_type->field()->type()->basic_type();
    +    }
    +    if (bt != type) {
    +      mismatched = true;
    +    }
    +  }
    +  assert(type != T_OBJECT || !unaligned, "unaligned access not supported with object type");
    +
    +  if (!is_store) {
         Node* p = NULL;
         // Try to constant fold a load from a constant field
         ciField* field = alias_type->field();
    @@ -2430,7 +2447,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas
           MemNode::MemOrd mo = is_volatile ? MemNode::acquire : MemNode::unordered;
           // To be valid, unsafe loads may depend on other conditions than
           // the one that guards them: pin the Load node
    -      p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, is_volatile);
    +      p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, is_volatile, unaligned, mismatched);
           // load value
           switch (type) {
           case T_BOOLEAN:
    @@ -2477,12 +2494,12 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas
     
         MemNode::MemOrd mo = is_volatile ? MemNode::release : MemNode::unordered;
         if (type != T_OBJECT ) {
    -      (void) store_to_memory(control(), adr, val, type, adr_type, mo, is_volatile);
    +      (void) store_to_memory(control(), adr, val, type, adr_type, mo, is_volatile, unaligned, mismatched);
         } else {
           // Possibly an oop being stored to Java heap or native memory
           if (!TypePtr::NULL_PTR->higher_equal(_gvn.type(heap_base_oop))) {
             // oop to Java heap.
    -        (void) store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo);
    +        (void) store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo, mismatched);
           } else {
             // We can't tell at compile time if we are storing in the Java heap or outside
             // of it. So we need to emit code to conditionally do the proper type of
    @@ -2494,11 +2511,11 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas
             __ if_then(heap_base_oop, BoolTest::ne, null(), PROB_UNLIKELY(0.999)); {
               // Sync IdealKit and graphKit.
               sync_kit(ideal);
    -          Node* st = store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo);
    +          Node* st = store_oop_to_unknown(control(), heap_base_oop, adr, adr_type, val, type, mo, mismatched);
               // Update IdealKit memory.
               __ sync_kit(this);
             } __ else_(); {
    -          __ store(__ ctrl(), adr, val, type, alias_type->index(), mo, is_volatile);
    +          __ store(__ ctrl(), adr, val, type, alias_type->index(), mo, is_volatile, mismatched);
             } __ end_if();
             // Final sync IdealKit and GraphKit.
             final_sync(ideal);
    diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp
    index d7da53ef871..863255dabdb 100644
    --- a/hotspot/src/share/vm/opto/memnode.cpp
    +++ b/hotspot/src/share/vm/opto/memnode.cpp
    @@ -72,8 +72,15 @@ void MemNode::dump_spec(outputStream *st) const {
       dump_adr_type(this, _adr_type, st);
     
       Compile* C = Compile::current();
    -  if( C->alias_type(_adr_type)->is_volatile() )
    +  if (C->alias_type(_adr_type)->is_volatile()) {
         st->print(" Volatile!");
    +  }
    +  if (_unaligned_access) {
    +    st->print(" unaligned");
    +  }
    +  if (_mismatched_access) {
    +    st->print(" mismatched");
    +  }
     }
     
     void MemNode::dump_adr_type(const Node* mem, const TypePtr* adr_type, outputStream *st) {
    @@ -2393,7 +2400,8 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) {
                  st->Opcode() == Op_StoreVector ||
                  Opcode() == Op_StoreVector ||
                  phase->C->get_alias_index(adr_type()) == Compile::AliasIdxRaw ||
    -             (Opcode() == Op_StoreL && st->Opcode() == Op_StoreI), // expanded ClearArrayNode
    +             (Opcode() == Op_StoreL && st->Opcode() == Op_StoreI) || // expanded ClearArrayNode
    +             (is_mismatched_access() || st->as_Store()->is_mismatched_access()),
                  "no mismatched stores, except on raw memory: %s %s", NodeClassNames[Opcode()], NodeClassNames[st->Opcode()]);
     
           if (st->in(MemNode::Address)->eqv_uncast(address) &&
    @@ -3213,6 +3221,9 @@ bool InitializeNode::detect_init_independence(Node* n, int& count) {
     // within the initialized memory.
     intptr_t InitializeNode::can_capture_store(StoreNode* st, PhaseTransform* phase, bool can_reshape) {
       const int FAIL = 0;
    +  if (st->is_unaligned_access()) {
    +    return FAIL;
    +  }
       if (st->req() != MemNode::ValueIn + 1)
         return FAIL;                // an inscrutable StoreNode (card mark?)
       Node* ctl = st->in(MemNode::Control);
    diff --git a/hotspot/src/share/vm/opto/memnode.hpp b/hotspot/src/share/vm/opto/memnode.hpp
    index 1abfede267b..f62ffad7da7 100644
    --- a/hotspot/src/share/vm/opto/memnode.hpp
    +++ b/hotspot/src/share/vm/opto/memnode.hpp
    @@ -39,11 +39,14 @@ class PhaseTransform;
     //------------------------------MemNode----------------------------------------
     // Load or Store, possibly throwing a NULL pointer exception
     class MemNode : public Node {
    +private:
    +  bool _unaligned_access; // Unaligned access from unsafe
    +  bool _mismatched_access; // Mismatched access from unsafe: byte read in integer array for instance
     protected:
     #ifdef ASSERT
       const TypePtr* _adr_type;     // What kind of memory is being addressed?
     #endif
    -  virtual uint size_of() const; // Size is bigger (ASSERT only)
    +  virtual uint size_of() const;
     public:
       enum { Control,               // When is it safe to do this load?
              Memory,                // Chunk of memory is being loaded from
    @@ -57,17 +60,17 @@ public:
       } MemOrd;
     protected:
       MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at )
    -    : Node(c0,c1,c2   ) {
    +    : Node(c0,c1,c2   ), _unaligned_access(false), _mismatched_access(false) {
         init_class_id(Class_Mem);
         debug_only(_adr_type=at; adr_type();)
       }
       MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at, Node *c3 )
    -    : Node(c0,c1,c2,c3) {
    +    : Node(c0,c1,c2,c3), _unaligned_access(false), _mismatched_access(false) {
         init_class_id(Class_Mem);
         debug_only(_adr_type=at; adr_type();)
       }
       MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at, Node *c3, Node *c4)
    -    : Node(c0,c1,c2,c3,c4) {
    +    : Node(c0,c1,c2,c3,c4), _unaligned_access(false), _mismatched_access(false) {
         init_class_id(Class_Mem);
         debug_only(_adr_type=at; adr_type();)
       }
    @@ -127,6 +130,11 @@ public:
       // the given memory state?  (The state may or may not be in(Memory).)
       Node* can_see_stored_value(Node* st, PhaseTransform* phase) const;
     
    +  void set_unaligned_access() { _unaligned_access = true; }
    +  bool is_unaligned_access() const { return _unaligned_access; }
    +  void set_mismatched_access() { _mismatched_access = true; }
    +  bool is_mismatched_access() const { return _mismatched_access; }
    +
     #ifndef PRODUCT
       static void dump_adr_type(const Node* mem, const TypePtr* adr_type, outputStream *st);
       virtual void dump_spec(outputStream *st) const;
    diff --git a/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.java b/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.java
    new file mode 100644
    index 00000000000..464c13cba56
    --- /dev/null
    +++ b/hotspot/test/compiler/intrinsics/unsafe/TestUnsafeUnalignedMismatchedAccesses.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 8136473
    + * @summary Mismatched stores on same slice possible with Unsafe.Put*Unaligned methods
    + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation TestUnsafeUnalignedMismatchedAccesses
    + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:+UnlockDiagnosticVMOptions -XX:-UseUnalignedAccesses TestUnsafeUnalignedMismatchedAccesses
    + *
    + */
    +
    +import java.lang.reflect.*;
    +import sun.misc.Unsafe;
    +
    +public class TestUnsafeUnalignedMismatchedAccesses {
    +
    +    private static final Unsafe UNSAFE;
    +
    +    static {
    +        try {
    +            Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
    +            unsafeField.setAccessible(true);
    +            UNSAFE = (Unsafe) unsafeField.get(null);
    +        }
    +        catch (Exception e) {
    +            throw new AssertionError(e);
    +        }
    +    }
    +
    +    static void test1(byte[] array) {
    +        array[0] = 0;
    +        UNSAFE.putIntUnaligned(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET, 0);
    +        array[0] = 0;
    +    }
    +
    +    static void test2(byte[] array) {
    +        array[0] = 0;
    +        UNSAFE.putIntUnaligned(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET+1, 0);
    +        array[0] = 0;
    +    }
    +
    +    static void test3(byte[] array) {
    +        array[0] = 0;
    +        UNSAFE.putIntUnaligned(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET+2, 0);
    +        array[0] = 0;
    +    }
    +
    +    static void test4(byte[] array) {
    +        array[0] = 0;
    +        UNSAFE.putIntUnaligned(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET+3, 0);
    +        array[0] = 0;
    +    }
    +
    +    static void test5(byte[] array) {
    +        array[0] = 0;
    +        UNSAFE.putInt(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET, 0);
    +        array[0] = 0;
    +    }
    +
    +    // unaligned access and non escaping allocation
    +    static void test6() {
    +        byte[] array = new byte[10];
    +        UNSAFE.putIntUnaligned(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET+1, -1);
    +        array[0] = 0;
    +    }
    +
    +    // unaligned access and non escaping allocation
    +    static int test7() {
    +        byte[] array = new byte[10];
    +        UNSAFE.putIntUnaligned(array, UNSAFE.ARRAY_BYTE_BASE_OFFSET+1, -1);
    +        array[0] = 0;
    +        array[2] = 0;
    +        return array[0] + array[1] + array[2] + array[3] + array[4];
    +    }
    +
    +    // unaligned access with vectorization
    +    static void test8(int[] src1, int[] src2, int[] dst) {
    +        for (int i = 0; i < dst.length-1; i++) {
    +            int res = src1[i] + src2[i];
    +            UNSAFE.putIntUnaligned(dst, UNSAFE.ARRAY_INT_BASE_OFFSET + i*4+1, res);
    +        }
    +    }
    +
    +    static public void main(String[] args) throws Exception {
    +        byte[] byte_array = new byte[100];
    +        int[] int_array = new int[100];
    +        Object[] obj_array = new Object[100];
    +        TestUnsafeUnalignedMismatchedAccesses test = new TestUnsafeUnalignedMismatchedAccesses();
    +        for (int i = 0; i < 20000; i++) {
    +            test1(byte_array);
    +            test2(byte_array);
    +            test3(byte_array);
    +            test4(byte_array);
    +            test5(byte_array);
    +            test6();
    +            test7();
    +            test8(int_array, int_array, int_array);
    +        }
    +    }
    +}
    
    From 206483e8b3a6992650461fe6e118131825ea8f2e Mon Sep 17 00:00:00 2001
    From: Sergey Bylokhov 
    Date: Sun, 18 Oct 2015 13:33:20 +0300
    Subject: [PATCH 09/75] 6815345: java.awt.Component.createImage(int width,int
     height) should remove behavioral optionality
    
    Reviewed-by: prr, ssadetsky
    ---
     .../share/classes/java/awt/Component.java     |  67 ++++++-----
     .../Component/CreateImage/CreateImage.java    | 111 ++++++++++++++++++
     2 files changed, 146 insertions(+), 32 deletions(-)
     create mode 100644 jdk/test/java/awt/Component/CreateImage/CreateImage.java
    
    diff --git a/jdk/src/java.desktop/share/classes/java/awt/Component.java b/jdk/src/java.desktop/share/classes/java/awt/Component.java
    index 3c50dceecce..72c459943b3 100644
    --- a/jdk/src/java.desktop/share/classes/java/awt/Component.java
    +++ b/jdk/src/java.desktop/share/classes/java/awt/Component.java
    @@ -3622,18 +3622,17 @@ public abstract class Component implements ImageObserver, MenuContainer,
         }
     
         /**
    -     * Creates an off-screen drawable image
    -     *     to be used for double buffering.
    -     * @param     width the specified width
    -     * @param     height the specified height
    -     * @return    an off-screen drawable image, which can be used for double
    -     *    buffering.  The return value may be null if the
    -     *    component is not displayable.  This will always happen if
    -     *    GraphicsEnvironment.isHeadless() returns
    -     *    true.
    +     * Creates an off-screen drawable image to be used for double buffering.
    +     *
    +     * @param  width the specified width
    +     * @param  height the specified height
    +     * @return an off-screen drawable image, which can be used for double
    +     *         buffering. The {@code null} value if the component is not
    +     *         displayable or {@code GraphicsEnvironment.isHeadless()} returns
    +     *         {@code true}.
          * @see #isDisplayable
          * @see GraphicsEnvironment#isHeadless
    -     * @since     1.0
    +     * @since 1.0
          */
         public Image createImage(int width, int height) {
             ComponentPeer peer = this.peer;
    @@ -3646,19 +3645,19 @@ public abstract class Component implements ImageObserver, MenuContainer,
         }
     
         /**
    -     * Creates a volatile off-screen drawable image
    -     *     to be used for double buffering.
    -     * @param     width the specified width.
    -     * @param     height the specified height.
    -     * @return    an off-screen drawable image, which can be used for double
    -     *    buffering.  The return value may be null if the
    -     *    component is not displayable.  This will always happen if
    -     *    GraphicsEnvironment.isHeadless() returns
    -     *    true.
    +     * Creates a volatile off-screen drawable image to be used for double
    +     * buffering.
    +     *
    +     * @param  width the specified width
    +     * @param  height the specified height
    +     * @return an off-screen drawable image, which can be used for double
    +     *         buffering. The {@code null} value if the component is not
    +     *         displayable or {@code GraphicsEnvironment.isHeadless()} returns
    +     *         {@code true}.
          * @see java.awt.image.VolatileImage
          * @see #isDisplayable
          * @see GraphicsEnvironment#isHeadless
    -     * @since     1.4
    +     * @since 1.4
          */
         public VolatileImage createVolatileImage(int width, int height) {
             ComponentPeer peer = this.peer;
    @@ -3674,22 +3673,26 @@ public abstract class Component implements ImageObserver, MenuContainer,
         }
     
         /**
    -     * Creates a volatile off-screen drawable image, with the given capabilities.
    -     * The contents of this image may be lost at any time due
    -     * to operating system issues, so the image must be managed
    -     * via the VolatileImage interface.
    -     * @param width the specified width.
    -     * @param height the specified height.
    -     * @param caps the image capabilities
    -     * @exception AWTException if an image with the specified capabilities cannot
    -     * be created
    -     * @return a VolatileImage object, which can be used
    -     * to manage surface contents loss and capabilities.
    +     * Creates a volatile off-screen drawable image, with the given
    +     * capabilities. The contents of this image may be lost at any time due to
    +     * operating system issues, so the image must be managed via the
    +     * {@code VolatileImage} interface.
    +     *
    +     * @param  width the specified width
    +     * @param  height the specified height
    +     * @param  caps the image capabilities
    +     * @return a VolatileImage object, which can be used to manage surface
    +     *         contents loss and capabilities. The {@code null} value if the
    +     *         component is not displayable or
    +     *         {@code GraphicsEnvironment.isHeadless()} returns {@code true}.
    +     * @throws AWTException if an image with the specified capabilities cannot
    +     *         be created
          * @see java.awt.image.VolatileImage
          * @since 1.4
          */
         public VolatileImage createVolatileImage(int width, int height,
    -                                             ImageCapabilities caps) throws AWTException {
    +                                             ImageCapabilities caps)
    +            throws AWTException {
             // REMIND : check caps
             return createVolatileImage(width, height);
         }
    diff --git a/jdk/test/java/awt/Component/CreateImage/CreateImage.java b/jdk/test/java/awt/Component/CreateImage/CreateImage.java
    new file mode 100644
    index 00000000000..aa977ce0ac5
    --- /dev/null
    +++ b/jdk/test/java/awt/Component/CreateImage/CreateImage.java
    @@ -0,0 +1,111 @@
    +/*
    + * 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.AWTException;
    +import java.awt.Button;
    +import java.awt.Component;
    +import java.awt.EventQueue;
    +import java.awt.Frame;
    +import java.awt.GraphicsEnvironment;
    +
    +import javax.swing.JButton;
    +
    +/**
    + * @test
    + * @bug 6815345
    + * @run main CreateImage
    + * @run main/othervm -Djava.awt.headless=true CreateImage
    + */
    +public final class CreateImage {
    +
    +    public static void main(final String[] args) throws Exception {
    +        EventQueue.invokeAndWait(CreateImage::test);
    +    }
    +
    +    private static void test() {
    +        final JButton jbutton1 = new JButton();
    +        final JButton jbutton2 = new JButton();
    +
    +        if (GraphicsEnvironment.isHeadless()) {
    +            checkCreateImage(jbutton1, true);
    +            checkCreateImage(jbutton2, true);
    +            return;
    +        }
    +
    +        final Frame frame = new Frame();
    +        final Button button1 = new Button();
    +        final Button button2 = new Button();
    +        try {
    +            // all components are not displayable
    +            checkCreateImage(frame, true);
    +            checkCreateImage(button1, true);
    +            checkCreateImage(button2, true);
    +            checkCreateImage(jbutton1, true);
    +            checkCreateImage(jbutton2, true);
    +
    +            // some components added to the non-displayable frame
    +            frame.add(button1);
    +            frame.add(jbutton1);
    +            checkCreateImage(button1, true);
    +            checkCreateImage(jbutton1, true);
    +            frame.pack();
    +
    +            // tests previously added components when the frame is displayable
    +            checkCreateImage(frame, false);
    +            checkCreateImage(button1, false);
    +            checkCreateImage(jbutton1, false);
    +
    +            // some components added to the displayable frame
    +            frame.add(button2);
    +            frame.add(jbutton2);
    +            checkCreateImage(button2, false);
    +            checkCreateImage(jbutton2, false);
    +
    +        } finally {
    +            frame.dispose();
    +        }
    +        // tests all components after the frame became non-displayable again
    +        checkCreateImage(frame, true);
    +        checkCreateImage(button1, true);
    +        checkCreateImage(button2, true);
    +        checkCreateImage(jbutton1, true);
    +        checkCreateImage(jbutton2, true);
    +    }
    +
    +    private static void checkCreateImage(final Component comp,
    +                                         final boolean isNull) {
    +        if ((comp.createImage(10, 10) != null) == isNull) {
    +            throw new RuntimeException("Image is wrong");
    +        }
    +        if ((comp.createVolatileImage(10, 10) != null) == isNull) {
    +            throw new RuntimeException("Image is wrong");
    +        }
    +        try {
    +            if ((comp.createVolatileImage(10, 10, null) != null) == isNull) {
    +                throw new RuntimeException("Image is wrong");
    +            }
    +        } catch (final AWTException ignored) {
    +            // this check is not applicable
    +        }
    +    }
    +}
    
    From fc56d44bca838fe8f852946875d363fbe5393ade Mon Sep 17 00:00:00 2001
    From: Erik Joelsson 
    Date: Tue, 20 Oct 2015 10:24:40 +0200
    Subject: [PATCH 10/75] 8139657: Incremental build of jdk.vm.ci-gensrc creates
     repeated entries in services file
    
    Reviewed-by: twisti
    ---
     hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk | 6 +++++-
     1 file changed, 5 insertions(+), 1 deletion(-)
    
    diff --git a/hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk b/hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk
    index bafe0a3b058..59750764d3f 100644
    --- a/hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk
    +++ b/hotspot/make/gensrc/Gensrc-jdk.vm.ci.gmk
    @@ -108,7 +108,11 @@ $(GENSRC_DIR)/_providers_converted: $(GENSRC_DIR)/_gensrc_proc_done
     	($(CD) $(GENSRC_DIR)/META-INF/jvmci.providers && \
     	    for i in $$($(LS)); do \
     	      c=$$($(CAT) $$i | $(TR) -d '\n\r'); \
    -	      $(ECHO) $$i >> $(GENSRC_DIR)/META-INF/services/$$c; \
    +	      $(ECHO) $$i >> $(GENSRC_DIR)/META-INF/services/$$c.tmp; \
    +	    done)
    +	($(CD) $(GENSRC_DIR)/META-INF/services && \
    +	    for i in $$($(LS) *.tmp); do \
    +	      $(MV) $$i $${i%.tmp}; \
     	    done)
     	$(TOUCH) $@
     
    
    From 1127171d12fbf88449682447644348f5f32b0b0e Mon Sep 17 00:00:00 2001
    From: Renjith Alexander 
    Date: Tue, 20 Oct 2015 12:42:21 +0300
    Subject: [PATCH 11/75] 8136592: [TEST_BUG] Fix 2 platform-specific closed
     regtests for jigsaw
    
    Reviewed-by: serb, yan
    ---
     .../GraphicsConfigTest.java                   | 159 ++++++++++++++++++
     .../FocusEmptyListTest.html                   |  47 ++++++
     .../FocusEmptyListTest.java                   |  96 +++++++++++
     3 files changed, 302 insertions(+)
     create mode 100644 jdk/test/java/awt/EmbeddedFrame/GraphicsConfigTest/GraphicsConfigTest.java
     create mode 100644 jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html
     create mode 100644 jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.java
    
    diff --git a/jdk/test/java/awt/EmbeddedFrame/GraphicsConfigTest/GraphicsConfigTest.java b/jdk/test/java/awt/EmbeddedFrame/GraphicsConfigTest/GraphicsConfigTest.java
    new file mode 100644
    index 00000000000..f2d56675c91
    --- /dev/null
    +++ b/jdk/test/java/awt/EmbeddedFrame/GraphicsConfigTest/GraphicsConfigTest.java
    @@ -0,0 +1,159 @@
    +/*
    + * 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
    + * 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 6356322
    + * @summary Tests that embedded frame's graphics configuration is updated
    + *          correctly when it is moved to another screen in multiscreen system,
    + *          XToolkit
    + * @author artem.ananiev@sun.com: area=awt.multiscreen
    + * @requires (os.family == "linux") | (os.family == "solaris")
    + * @modules java.desktop/sun.awt
    + *          java.desktop/sun.awt.X11
    + *          java.desktop/java.awt.peer
    + * @run main GraphicsConfigTest
    + */
    +
    +import java.awt.*;
    +import java.awt.peer.*;
    +import java.lang.reflect.*;
    +import java.util.*;
    +import sun.awt.*;
    +
    +public class GraphicsConfigTest {
    +
    +    private static void init()
    +        throws InterruptedException, AWTException {
    +        if (!isXToolkit()) {
    +            System.err.println("The test should be run only on XToolkit");
    +            return;
    +        }
    +
    +        GraphicsEnvironment ge =
    +                GraphicsEnvironment.getLocalGraphicsEnvironment();
    +        GraphicsDevice[] gds = ge.getScreenDevices();
    +        if (gds.length < 2) {
    +            System.err.println("The test should be run only in"
    +                + " multiscreen configuration");
    +            return;
    +        }
    +
    +        boolean xinerama = Arrays.stream(gds)
    +            .map((gd) -> gd.getDefaultConfiguration().getBounds())
    +            .filter((r) -> r.x != 0 || r.y != 0).findFirst().isPresent();
    +
    +        if (!xinerama) {
    +            System.err.println("The test should be run only with Xinerama ON");
    +            return;
    +        }
    +
    +        Rectangle r0 = gds[0].getDefaultConfiguration().getBounds();
    +        Rectangle r1 = gds[1].getDefaultConfiguration().getBounds();
    +
    +        System.setProperty("sun.awt.xembedserver", "true");
    +        Frame f = new Frame("F");
    +        try {
    +            final Robot robot = new Robot();
    +
    +            f.setBounds(r0.x + 100, r0.y + 100, 200, 200);
    +            f.setVisible(true);
    +            robot.waitForIdle();
    +            Thread.sleep(1000);
    +
    +            Canvas c = new Canvas();
    +            f.add(c);
    +            AWTAccessor.ComponentAccessor acc =
    +                        AWTAccessor.getComponentAccessor();
    +            WindowIDProvider wip = acc.getPeer(c);
    +            long h = wip.getWindow();
    +
    +            EmbeddedFrame e = createEmbeddedFrame(h);
    +            acc.getPeer(e).setBoundsPrivate(0, 0, 100,
    +                100); // triggers XConfigureEvent
    +            e.registerListeners();
    +            e.setVisible(true);
    +            robot.waitForIdle();
    +            Thread.sleep(1000);
    +
    +            if (!checkGC(f, e)) {
    +                throw new RuntimeException("Failed at checkpoint 1");
    +            }
    +
    +            f.setLocation(r1.x + 100, r1.y + 100);
    +            Thread.sleep(100);
    +            acc.getPeer(e).setBoundsPrivate(0, 0, 101,
    +                101); // triggers XConfigureEvent
    +            robot.waitForIdle();
    +            Thread.sleep(1000);
    +
    +            if (!checkGC(f, e)) {
    +                throw new RuntimeException("Failed at checkpoint 2");
    +            }
    +
    +            f.setLocation(r0.x + 100, r0.y + 100);
    +            Thread.sleep(100);
    +            acc.getPeer(e).setBoundsPrivate(0, 0, 102,
    +                102); // triggers XConfigureEvent
    +            robot.waitForIdle();
    +            Thread.sleep(1000);
    +
    +            if (!checkGC(f, e)) {
    +                throw new RuntimeException("Failed at checkpoint 3");
    +            }
    +
    +        } finally {
    +            f.dispose();
    +        }
    +    }
    +
    +    private static boolean isXToolkit() {
    +        return Toolkit.getDefaultToolkit().getClass()
    +                        .getName().equals("sun.awt.X11.XToolkit");
    +    }
    +
    +    private static EmbeddedFrame createEmbeddedFrame(long window) {
    +        try {
    +            Class cl = Class.forName("sun.awt.X11.XEmbeddedFrame");
    +            Constructor cons = cl.getConstructor(
    +                new Class[]{Long.TYPE, Boolean.TYPE});
    +            return (EmbeddedFrame) cons.newInstance(new Object[]{window, true});
    +        } catch (Exception e) {
    +            e.printStackTrace();
    +            throw new RuntimeException("Can't create embedded frame");
    +        }
    +    }
    +
    +    private static boolean checkGC(Component c, Component d) {
    +        GraphicsConfiguration g1 = c.getGraphicsConfiguration();
    +        System.err.println(g1);
    +        GraphicsConfiguration g2 = d.getGraphicsConfiguration();
    +        System.err.println(g2);
    +
    +        return g1.equals(g2);
    +    }
    +
    +    public static void main(String args[]) throws InterruptedException, AWTException {
    +        init();
    +    }
    +}
    diff --git a/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html b/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html
    new file mode 100644
    index 00000000000..5bbd8f7f197
    --- /dev/null
    +++ b/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.html
    @@ -0,0 +1,47 @@
    +
    +
    +
    +
    + FocusEmptyListTest 
    +
    +
    +
    +

    FocusEmptyListTest
    Bug ID: 6387275

    + +

    This is an AUTOMATIC test, simply wait for completion

    + + + + + diff --git a/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.java b/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.java new file mode 100644 index 00000000000..59d8c61269c --- /dev/null +++ b/jdk/test/java/awt/List/FocusEmptyListTest/FocusEmptyListTest.java @@ -0,0 +1,96 @@ +/* + * 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 + * 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 6387275 + @summary List: the focus is at the top of the first item, XAWT + @author Dmitry.Cherepanov@SUN.COM area=awt.list + @run applet FocusEmptyListTest.html +*/ + +import java.applet.Applet; +import java.awt.*; +import java.lang.reflect.*; +import java.awt.peer.ListPeer; + +import sun.awt.AWTAccessor; + +public class FocusEmptyListTest extends Applet { + + public void init() { + setLayout(new BorderLayout()); + }//End init() + + public void start() { + boolean isXToolkit = Toolkit.getDefaultToolkit() + .getClass().getName().equals("sun.awt.X11.XToolkit"); + if (!isXToolkit) { + System.out.println("The test is XAWT-only."); + return; + } + + List list = new List(); + Object isIndexDisplayed = null; + setLayout(new FlowLayout()); + + getToolkit().addAWTEventListener(System.out::println, + AWTEvent.FOCUS_EVENT_MASK | AWTEvent.WINDOW_FOCUS_EVENT_MASK); + + add(list); + list.add("item1"); + + setSize(200, 200); + setVisible(true); + validate(); + + list.removeAll(); + + try { + + // peer = List.getPeer() + ListPeer peer = AWTAccessor.getComponentAccessor().getPeer(list); + System.out.println("peer = " + peer); + Class peerClass = peer.getClass(); + System.out.println("peer's class = " + peerClass); + + // isIndexDisplayed = peer.isIndexDisplayed(-1) + Method isIndexDisplayedM + = peerClass.getDeclaredMethod("isIndexDisplayed", Integer.TYPE); + System.out.println("method = " + isIndexDisplayedM); + isIndexDisplayedM.setAccessible(true); + isIndexDisplayed = isIndexDisplayedM.invoke(peer, -1); + System.out.println("isIndexDisplayed=" + isIndexDisplayed); + + } catch (Throwable thr) { + throw new RuntimeException("TEST FAILED: " + thr); + } + + if ((Boolean) isIndexDisplayed) { + throw new RuntimeException("TEST FAILED: -1 should be" + + " invisible index"); + } + + }// start() + +}// class AutomaticAppletTest From d1544f66ebadfafcfb9c9d79442c19aa99145c6b Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 20 Oct 2015 15:42:59 +0300 Subject: [PATCH 12/75] 8011616: JWindow.getLocation and JWindow.getLocationOnScreen return different values on Unity Reviewed-by: alexsch, serb --- .../unix/classes/sun/awt/X11/XWindow.java | 3 + .../ScreenLocation/ScreenLocationTest.java | 92 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 jdk/test/java/awt/Window/ScreenLocation/ScreenLocationTest.java diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java index 597020da9e3..a90a938086d 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java @@ -992,10 +992,13 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { // if ( Check if it's a resize, a move, or a stacking order change ) // { Rectangle bounds = getBounds(); + final ComponentAccessor acc = AWTAccessor.getComponentAccessor(); if (!bounds.getSize().equals(oldBounds.getSize())) { + acc.setSize(target, bounds.width, bounds.height); postEventToEventQueue(new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_RESIZED)); } if (!bounds.getLocation().equals(oldBounds.getLocation())) { + acc.setLocation(target, bounds.x, bounds.y); postEventToEventQueue(new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_MOVED)); } // } diff --git a/jdk/test/java/awt/Window/ScreenLocation/ScreenLocationTest.java b/jdk/test/java/awt/Window/ScreenLocation/ScreenLocationTest.java new file mode 100644 index 00000000000..ef89ef0c0cb --- /dev/null +++ b/jdk/test/java/awt/Window/ScreenLocation/ScreenLocationTest.java @@ -0,0 +1,92 @@ +/* + * 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 8011616 + @summary JWindow.getLocation and JWindow.getLocationOnScreen return different + values on Unity + @author Semyon Sadetsky + */ + +import java.awt.*; + +public class ScreenLocationTest { + + + public static void main(String[] args) throws Exception { + testLocation(); + testSize(); + System.out.println("ok"); + } + + public static void testLocation() throws Exception { + Window window = new Window((Frame) null); + window.setSize(100, 100); + window.setLocation(0, 0); + window.setVisible(true); + + Robot robot = new Robot(); + robot.delay(200); + robot.waitForIdle(); + + Point location1 = window.getLocation(); + Point location2 = window.getLocationOnScreen(); + window.setLocation(10000, 10000); + + if (!location1.equals(location2)) { + window.dispose(); + throw new RuntimeException("getLocation is different"); + } + + robot.delay(200); + robot.waitForIdle(); + location1 = window.getLocation(); + location2 = window.getLocationOnScreen(); + + if (!location1.equals(location2)) { + window.dispose(); + throw new RuntimeException("getLocation is different"); + } + + window.dispose(); + } + + public static void testSize() throws Exception { + Window window = new Window((Frame) null); + window.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE); + window.setVisible(true); + + Robot robot = new Robot(); + robot.delay(200); + robot.waitForIdle(); + + Dimension size = window.getSize(); + if (size.width == Integer.MAX_VALUE || + size.height == Integer.MAX_VALUE) { + window.dispose(); + throw new RuntimeException("size is wrong"); + } + + window.dispose(); + } +} From d910e3843fb093117b7118371afc1e4efc71afac Mon Sep 17 00:00:00 2001 From: Semyon Sadetsky Date: Tue, 20 Oct 2015 15:59:51 +0300 Subject: [PATCH 13/75] 8022334: After calling frame.toBack() dialog goes to the back on Ubuntu 12.04 Reviewed-by: alexsch, serb --- .../unix/classes/sun/awt/X11/XWindow.java | 3 +- .../MultiWindowApp/MultiWindowAppTest.java | 81 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 jdk/test/java/awt/Window/MultiWindowApp/MultiWindowAppTest.java diff --git a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java index a90a938086d..42a03359f1f 100644 --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XWindow.java @@ -272,7 +272,8 @@ class XWindow extends XBaseWindow implements X11ComponentPeer { } protected String[] getWMClass() { - return new String[] {XToolkit.getCorrectXIDString(getClass().getName()), XToolkit.getAWTAppClassName()}; + return new String[] {XToolkit.getAWTAppClassName(), + XToolkit.getAWTAppClassName()}; } void setReparented(boolean newValue) { diff --git a/jdk/test/java/awt/Window/MultiWindowApp/MultiWindowAppTest.java b/jdk/test/java/awt/Window/MultiWindowApp/MultiWindowAppTest.java new file mode 100644 index 00000000000..41b4b7fbe5d --- /dev/null +++ b/jdk/test/java/awt/Window/MultiWindowApp/MultiWindowAppTest.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. + */ + +/** + * @test @summary After calling frame.toBack() dialog goes to the back on Ubuntu 12.04 + * @bug 8022334 + * @author Semyon Sadetsky + * @run main MultiWindowAppTest + */ + +import java.awt.*; + +public class MultiWindowAppTest { + + public static void main(String[] args) throws Exception { + Window win1 = new Frame(); + Window win2 = new Dialog((Frame) null); + + win1.setBounds(100, 100, 200, 200); + win1.setBackground(Color.RED); + win1.setVisible(true); + + Robot robot = new Robot(); + robot.delay(200); + robot.waitForIdle(); + + win2.setBounds(win1.getBounds()); + win2.setVisible(true); + + robot.delay(200); + robot.waitForIdle(); + + win1.toFront(); + robot.delay(200); + robot.waitForIdle(); + + Point point = win1.getLocationOnScreen(); + Color color = robot.getPixelColor(point.x + 100, point.y + 100); + + if(!color.equals(Color.RED)) { + win1.dispose(); + win2.dispose(); + throw new RuntimeException("Window was not sent to front."); + } + + win1.toBack(); + robot.delay(200); + robot.waitForIdle(); + + color = robot.getPixelColor(point.x + 100, point.y + 100); + + win1.dispose(); + win2.dispose(); + + if(color.equals(Color.RED)) { + throw new RuntimeException("Window was not sent to back."); + } + + System.out.println("ok"); + } +} From 69da2a817d28868dae9fdb6f099e337a4da0f74f Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Tue, 20 Oct 2015 16:55:08 +0300 Subject: [PATCH 14/75] 8130136: Swing window sometimes fails to repaint partially when it becomes exposed Reviewed-by: alexp, serb --- .../libawt/java2d/windows/GDIWindowSurfaceData.cpp | 8 +++++--- .../libawt/java2d/windows/GDIWindowSurfaceData.h | 3 ++- .../native/libawt/windows/awt_Component.cpp | 14 +++++++------- .../windows/native/libawt/windows/awt_Component.h | 6 +++--- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/jdk/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.cpp b/jdk/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.cpp index b52dce038a0..95e737340fb 100644 --- a/jdk/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.cpp @@ -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 @@ -114,8 +114,9 @@ void SetupThreadGraphicsInfo(JNIEnv *env, GDIWinSDOps *wsdo) { // which may've been disposed by this time, and we have // no means of checking against it. if (oldhDC != NULL) { - MoveDCToPassiveList(oldhDC); + MoveDCToPassiveList(oldhDC, info->hWnd); info->hDC = NULL; + info->hWnd = NULL; } if (wsdo->window != NULL){ @@ -150,6 +151,7 @@ void SetupThreadGraphicsInfo(JNIEnv *env, GDIWinSDOps *wsdo) { // Finally, set these new values in the info for this thread info->hDC = hDC; + info->hWnd = wsdo->window; } // cached brush and pen are not associated with any DC, and can be @@ -187,7 +189,7 @@ void DisposeThreadGraphicsInfo(JNIEnv *env, jlong tgi) { if (info->hDC != NULL) { // move the DC from the active dcs list to // the passive dc list to be released later - MoveDCToPassiveList(info->hDC); + MoveDCToPassiveList(info->hDC, info->hWnd); } if (info->clip != NULL) { diff --git a/jdk/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.h b/jdk/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.h index 3dfaa161c02..a954874e9c8 100644 --- a/jdk/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.h +++ b/jdk/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, 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 @@ -196,6 +196,7 @@ extern "C" { */ typedef struct { HDC hDC; + HWND hWnd; GDIWinSDOps *wsdo; LONG wsdoTimeStamp; // wsdo creation time stamp. // Other threads may deallocate wsdo diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp index 6b1c1255319..b234ec0221b 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp @@ -1382,7 +1382,7 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) case WM_AWT_RELEASEDC: { HDC hDC = (HDC)wParam; - MoveDCToPassiveList(hDC); + MoveDCToPassiveList(hDC, GetHWnd()); ReleaseDCList(GetHWnd(), passiveDCList); mr = mrConsume; break; @@ -7165,8 +7165,8 @@ void DCList::AddDCItem(DCItem *newItem) } /** - * Given a DC, remove it from the DC list and return - * TRUE if it exists on the current list. Otherwise + * Given a DC and window handle, remove the DC from the DC list + * and return TRUE if it exists on the current list. Otherwise * return FALSE. * A DC may not exist on the list because it has already * been released elsewhere (for example, the window @@ -7174,14 +7174,14 @@ void DCList::AddDCItem(DCItem *newItem) * thread may also want to release a DC when it notices that * its DC is obsolete for the current window). */ -DCItem *DCList::RemoveDC(HDC hDC) +DCItem *DCList::RemoveDC(HDC hDC, HWND hWnd) { listLock.Enter(); DCItem **prevPtrPtr = &head; DCItem *listPtr = head; while (listPtr) { DCItem *nextPtr = listPtr->next; - if (listPtr->hDC == hDC) { + if (listPtr->hDC == hDC && listPtr->hWnd == hWnd) { *prevPtrPtr = nextPtr; break; } @@ -7235,9 +7235,9 @@ void DCList::RealizePalettes(int screen) listLock.Leave(); } -void MoveDCToPassiveList(HDC hDC) { +void MoveDCToPassiveList(HDC hDC, HWND hWnd) { DCItem *removedDC; - if ((removedDC = activeDCList.RemoveDC(hDC)) != NULL) { + if ((removedDC = activeDCList.RemoveDC(hDC, hWnd)) != NULL) { passiveDCList.AddDCItem(removedDC); } } diff --git a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h index 9fe2754142b..f09b41f5b54 100644 --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Component.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -900,13 +900,13 @@ public: void AddDC(HDC hDC, HWND hWnd); void AddDCItem(DCItem *newItem); - DCItem *RemoveDC(HDC hDC); + DCItem *RemoveDC(HDC hDC, HWND hWnd); DCItem *RemoveAllDCs(HWND hWnd); void RealizePalettes(int screen); }; void ReleaseDCList(HWND hwnd, DCList &list); -void MoveDCToPassiveList(HDC hDC); +void MoveDCToPassiveList(HDC hDC, HWND hWnd); #include "ObjectList.h" From 8668b408392376ae363c9b11b28d8a62ef6b3510 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Tue, 20 Oct 2015 18:07:24 +0200 Subject: [PATCH 15/75] 8137167: JEP165: Compiler Control: Implementation task Compiler Control JEP Reviewed-by: roland, twisti, zmajo, simonis --- test/lib/sun/hotspot/WhiteBox.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/lib/sun/hotspot/WhiteBox.java b/test/lib/sun/hotspot/WhiteBox.java index 0b0f096e30d..2af9e12d0f3 100644 --- a/test/lib/sun/hotspot/WhiteBox.java +++ b/test/lib/sun/hotspot/WhiteBox.java @@ -166,6 +166,8 @@ public class WhiteBox { // Compiler public native int matchesMethod(Executable method, String pattern); + public native int matchesInline(Executable method, String pattern); + public native boolean shouldPrintAssembly(Executable method); public native int deoptimizeFrames(boolean makeNotEntrant); public native void deoptimizeAll(); public boolean isMethodCompiled(Executable method) { From 5a5faf94bf1fecf10cb392b85740621f6c815f08 Mon Sep 17 00:00:00 2001 From: Nils Eliasson Date: Tue, 20 Oct 2015 18:07:28 +0200 Subject: [PATCH 16/75] 8137167: JEP165: Compiler Control: Implementation task Compiler Control JEP Reviewed-by: roland, twisti, zmajo, simonis --- hotspot/src/share/vm/c1/c1_Compilation.cpp | 11 +- hotspot/src/share/vm/c1/c1_Compilation.hpp | 4 +- hotspot/src/share/vm/c1/c1_Compiler.cpp | 4 +- hotspot/src/share/vm/c1/c1_Compiler.hpp | 3 +- hotspot/src/share/vm/c1/c1_GraphBuilder.cpp | 13 +- hotspot/src/share/vm/ci/ciEnv.cpp | 20 +- hotspot/src/share/vm/ci/ciEnv.hpp | 5 +- hotspot/src/share/vm/ci/ciMethod.cpp | 56 +- hotspot/src/share/vm/ci/ciMethod.hpp | 12 +- hotspot/src/share/vm/classfile/vmSymbols.cpp | 28 +- hotspot/src/share/vm/classfile/vmSymbols.hpp | 2 +- hotspot/src/share/vm/code/nmethod.cpp | 15 +- .../share/vm/compiler/abstractCompiler.hpp | 48 +- .../src/share/vm/compiler/compileBroker.cpp | 63 +- .../src/share/vm/compiler/compileBroker.hpp | 13 +- hotspot/src/share/vm/compiler/compileTask.cpp | 14 + .../share/vm/compiler/compilerDirectives.cpp | 502 +++++++++ .../share/vm/compiler/compilerDirectives.hpp | 186 ++++ .../src/share/vm/compiler/compilerOracle.cpp | 23 +- .../src/share/vm/compiler/compilerOracle.hpp | 6 +- .../share/vm/compiler/directivesParser.cpp | 726 +++++++++++++ .../share/vm/compiler/directivesParser.hpp | 139 +++ .../src/share/vm/compiler/methodMatcher.cpp | 101 ++ .../src/share/vm/compiler/methodMatcher.hpp | 59 +- hotspot/src/share/vm/jvmci/jvmciCompiler.cpp | 2 +- hotspot/src/share/vm/jvmci/jvmciCompiler.hpp | 2 +- hotspot/src/share/vm/opto/block.cpp | 3 +- hotspot/src/share/vm/opto/block.hpp | 1 - hotspot/src/share/vm/opto/bytecodeInfo.cpp | 6 +- hotspot/src/share/vm/opto/c2_globals.hpp | 4 +- hotspot/src/share/vm/opto/c2compiler.cpp | 5 +- hotspot/src/share/vm/opto/c2compiler.hpp | 3 +- hotspot/src/share/vm/opto/chaitin.cpp | 2 +- hotspot/src/share/vm/opto/compile.cpp | 49 +- hotspot/src/share/vm/opto/compile.hpp | 25 +- .../src/share/vm/opto/idealGraphPrinter.cpp | 24 +- .../src/share/vm/opto/idealGraphPrinter.hpp | 11 +- hotspot/src/share/vm/opto/library_call.cpp | 5 +- hotspot/src/share/vm/opto/output.cpp | 4 +- hotspot/src/share/vm/opto/parse2.cpp | 6 +- hotspot/src/share/vm/opto/runtime.cpp | 8 +- hotspot/src/share/vm/opto/superword.cpp | 5 +- hotspot/src/share/vm/prims/jni.cpp | 4 + hotspot/src/share/vm/prims/whitebox.cpp | 58 +- hotspot/src/share/vm/runtime/globals.hpp | 11 +- hotspot/src/share/vm/runtime/init.cpp | 6 +- hotspot/src/share/vm/runtime/mutexLocker.cpp | 2 + hotspot/src/share/vm/runtime/mutexLocker.hpp | 1 + .../src/share/vm/runtime/sharedRuntime.cpp | 6 + .../src/share/vm/runtime/vm_operations.cpp | 1 - .../share/vm/services/diagnosticCommand.cpp | 39 + .../share/vm/services/diagnosticCommand.hpp | 86 ++ hotspot/src/share/vm/shark/sharkCompiler.cpp | 5 +- hotspot/src/share/vm/shark/sharkCompiler.hpp | 3 +- hotspot/src/share/vm/utilities/json.cpp | 956 ++++++++++++++++++ hotspot/src/share/vm/utilities/json.hpp | 127 +++ .../compilercontrol/InlineMatcherTest.java | 173 ++++ ...stCompilerDirectivesCompatibilityBase.java | 125 +++ ...ilerDirectivesCompatibilityCommandOff.java | 80 ++ ...pilerDirectivesCompatibilityCommandOn.java | 80 ++ ...stCompilerDirectivesCompatibilityFlag.java | 80 ++ .../compiler/compilercontrol/control_off.txt | 7 + .../compiler/compilercontrol/control_on.txt | 7 + .../compiler/CompilerDirectivesDCMDTest.java | 158 +++ .../serviceability/dcmd/compiler/control1.txt | 17 + .../serviceability/dcmd/compiler/control2.txt | 22 + 66 files changed, 3965 insertions(+), 307 deletions(-) create mode 100644 hotspot/src/share/vm/compiler/compilerDirectives.cpp create mode 100644 hotspot/src/share/vm/compiler/compilerDirectives.hpp create mode 100644 hotspot/src/share/vm/compiler/directivesParser.cpp create mode 100644 hotspot/src/share/vm/compiler/directivesParser.hpp create mode 100644 hotspot/src/share/vm/utilities/json.cpp create mode 100644 hotspot/src/share/vm/utilities/json.hpp create mode 100644 hotspot/test/compiler/compilercontrol/InlineMatcherTest.java create mode 100644 hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java create mode 100644 hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java create mode 100644 hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java create mode 100644 hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java create mode 100644 hotspot/test/compiler/compilercontrol/control_off.txt create mode 100644 hotspot/test/compiler/compilercontrol/control_on.txt create mode 100644 hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java create mode 100644 hotspot/test/serviceability/dcmd/compiler/control1.txt create mode 100644 hotspot/test/serviceability/dcmd/compiler/control2.txt diff --git a/hotspot/src/share/vm/c1/c1_Compilation.cpp b/hotspot/src/share/vm/c1/c1_Compilation.cpp index 58255ba27e0..fc805143d92 100644 --- a/hotspot/src/share/vm/c1/c1_Compilation.cpp +++ b/hotspot/src/share/vm/c1/c1_Compilation.cpp @@ -34,6 +34,7 @@ #include "c1/c1_ValueStack.hpp" #include "code/debugInfoRec.hpp" #include "compiler/compileLog.hpp" +#include "compiler/compilerDirectives.hpp" #include "runtime/sharedRuntime.hpp" typedef enum { @@ -418,9 +419,9 @@ void Compilation::install_code(int frame_size) { exception_handler_table(), implicit_exception_table(), compiler(), - _env->comp_level(), has_unsafe_access(), - SharedRuntime::is_wide_vector(max_vector_size()) + SharedRuntime::is_wide_vector(max_vector_size()), + directive() ); } @@ -445,7 +446,7 @@ void Compilation::compile_method() { dependency_recorder()->assert_evol_method(method()); } - if (method()->break_at_execute()) { + if (directive()->BreakAtCompileOption) { BREAKPOINT; } @@ -534,9 +535,10 @@ void Compilation::generate_exception_handler_table() { Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* method, - int osr_bci, BufferBlob* buffer_blob) + int osr_bci, BufferBlob* buffer_blob, DirectiveSet* directive) : _compiler(compiler) , _env(env) +, _directive(directive) , _log(env->log()) , _method(method) , _osr_bci(osr_bci) @@ -587,7 +589,6 @@ Compilation::~Compilation() { _env->set_compiler_data(NULL); } - void Compilation::add_exception_handlers_for_pco(int pco, XHandlers* exception_handlers) { #ifndef PRODUCT if (PrintExceptionHandlers && Verbose) { diff --git a/hotspot/src/share/vm/c1/c1_Compilation.hpp b/hotspot/src/share/vm/c1/c1_Compilation.hpp index 6ecd26477e0..a20ea9f8def 100644 --- a/hotspot/src/share/vm/c1/c1_Compilation.hpp +++ b/hotspot/src/share/vm/c1/c1_Compilation.hpp @@ -67,6 +67,7 @@ class Compilation: public StackObj { int _next_id; int _next_block_id; AbstractCompiler* _compiler; + DirectiveSet* _directive; ciEnv* _env; CompileLog* _log; ciMethod* _method; @@ -118,7 +119,7 @@ class Compilation: public StackObj { public: // creation Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* method, - int osr_bci, BufferBlob* buffer_blob); + int osr_bci, BufferBlob* buffer_blob, DirectiveSet* directive); ~Compilation(); @@ -128,6 +129,7 @@ class Compilation: public StackObj { // accessors ciEnv* env() const { return _env; } + DirectiveSet* directive() const { return _directive; } CompileLog* log() const { return _log; } AbstractCompiler* compiler() const { return _compiler; } bool has_exception_handlers() const { return _has_exception_handlers; } diff --git a/hotspot/src/share/vm/c1/c1_Compiler.cpp b/hotspot/src/share/vm/c1/c1_Compiler.cpp index 13a8354b4c9..8377dbcb56c 100644 --- a/hotspot/src/share/vm/c1/c1_Compiler.cpp +++ b/hotspot/src/share/vm/c1/c1_Compiler.cpp @@ -238,7 +238,7 @@ bool Compiler::is_intrinsic_supported(methodHandle method) { return true; } -void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) { +void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci, DirectiveSet* directive) { BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob(); assert(buffer_blob != NULL, "Must exist"); // invoke compilation @@ -247,7 +247,7 @@ void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) { // of Compilation to occur before we release the any // competing compiler thread ResourceMark rm; - Compilation c(this, env, method, entry_bci, buffer_blob); + Compilation c(this, env, method, entry_bci, buffer_blob, directive); } } diff --git a/hotspot/src/share/vm/c1/c1_Compiler.hpp b/hotspot/src/share/vm/c1/c1_Compiler.hpp index 96a6bad4f5e..5ac2ade31fc 100644 --- a/hotspot/src/share/vm/c1/c1_Compiler.hpp +++ b/hotspot/src/share/vm/c1/c1_Compiler.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_C1_C1_COMPILER_HPP #include "compiler/abstractCompiler.hpp" +#include "compiler/compilerDirectives.hpp" // There is one instance of the Compiler per CompilerThread. @@ -50,7 +51,7 @@ class Compiler: public AbstractCompiler { virtual void initialize(); // Compilation entry point for methods - virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci); + virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive); // Print compilation timers and statistics virtual void print_timers(); diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp index 7144a6d5837..5b27aae2a05 100644 --- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp @@ -3365,7 +3365,7 @@ const char* GraphBuilder::check_can_parse(ciMethod* callee) const { // negative filter: should callee NOT be inlined? returns NULL, ok to inline, or rejection msg const char* GraphBuilder::should_not_inline(ciMethod* callee) const { - if ( callee->should_not_inline()) return "disallowed by CompileCommand"; + if ( compilation()->directive()->should_not_inline(callee)) return "disallowed by CompileCommand"; if ( callee->dont_inline()) return "don't inline by annotation"; return NULL; } @@ -3494,8 +3494,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) { { VM_ENTRY_MARK; methodHandle mh(THREAD, callee->get_Method()); - methodHandle ct(THREAD, method()->get_Method()); - is_available = _compilation->compiler()->is_intrinsic_available(mh, ct); + is_available = _compilation->compiler()->is_intrinsic_available(mh, _compilation->directive()); } if (!is_available) { @@ -3690,13 +3689,14 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode } // now perform tests that are based on flag settings - if (callee->force_inline() || callee->should_inline()) { + bool inlinee_by_directive = compilation()->directive()->should_inline(callee); + if (callee->force_inline() || inlinee_by_directive) { if (inline_level() > MaxForceInlineLevel ) INLINE_BAILOUT("MaxForceInlineLevel"); if (recursive_inline_level(callee) > MaxRecursiveInlineLevel) INLINE_BAILOUT("recursive inlining too deep"); const char* msg = ""; if (callee->force_inline()) msg = "force inline by annotation"; - if (callee->should_inline()) msg = "force inline by CompileCommand"; + if (inlinee_by_directive) msg = "force inline by CompileCommand"; print_inlining(callee, msg); } else { // use heuristic controls on inlining @@ -4207,7 +4207,8 @@ void GraphBuilder::print_inlining(ciMethod* callee, const char* msg, bool succes event.commit(); } #endif // INCLUDE_TRACE - if (!PrintInlining && !compilation()->method()->has_option("PrintInlining")) { + + if (!compilation()->directive()->PrintInliningOption) { return; } CompileTask::print_inlining_tty(callee, scope()->level(), bci(), msg); diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index 6473606d499..4e1d2e99bd1 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -38,7 +38,8 @@ #include "code/scopeDesc.hpp" #include "compiler/compileBroker.hpp" #include "compiler/compileLog.hpp" -#include "compiler/compilerOracle.hpp" +#include "compiler/compilerDirectives.hpp" +#include "compiler/disassembler.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "interpreter/linkResolver.hpp" #include "memory/allocation.inline.hpp" @@ -956,9 +957,9 @@ void ciEnv::register_method(ciMethod* target, ExceptionHandlerTable* handler_table, ImplicitExceptionTable* inc_table, AbstractCompiler* compiler, - int comp_level, bool has_unsafe_access, bool has_wide_vectors, + DirectiveSet* directives, RTMState rtm_state) { VM_ENTRY_MARK; nmethod* nm = NULL; @@ -1034,11 +1035,20 @@ void ciEnv::register_method(ciMethod* target, debug_info(), dependencies(), code_buffer, frame_words, oop_map_set, handler_table, inc_table, - compiler, comp_level); + compiler, task()->comp_level()); + // Free codeBlobs code_buffer->free_blob(); if (nm != NULL) { + bool printnmethods = directives->PrintAssemblyOption || directives->PrintNMethodsOption; + if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) { + nm->print_nmethod(printnmethods); + } + if (directives->PrintAssemblyOption) { + Disassembler::decode(nm); + } + nm->set_has_unsafe_access(has_unsafe_access); nm->set_has_wide_vectors(has_wide_vectors); #if INCLUDE_RTM_OPT @@ -1069,7 +1079,7 @@ void ciEnv::register_method(ciMethod* target, char *method_name = method->name_and_sig_as_C_string(); ttyLocker ttyl; tty->print_cr("Installing method (%d) %s ", - comp_level, + task()->comp_level(), method_name); } // Allow the code to be executed @@ -1080,7 +1090,7 @@ void ciEnv::register_method(ciMethod* target, char *method_name = method->name_and_sig_as_C_string(); ttyLocker ttyl; tty->print_cr("Installing osr method (%d) %s @ %d", - comp_level, + task()->comp_level(), method_name, entry_bci); } diff --git a/hotspot/src/share/vm/ci/ciEnv.hpp b/hotspot/src/share/vm/ci/ciEnv.hpp index 29e52c352af..f50a502db0b 100644 --- a/hotspot/src/share/vm/ci/ciEnv.hpp +++ b/hotspot/src/share/vm/ci/ciEnv.hpp @@ -32,9 +32,11 @@ #include "code/dependencies.hpp" #include "code/exceptionHandlerTable.hpp" #include "compiler/oopMap.hpp" +#include "compiler/compilerDirectives.hpp" #include "runtime/thread.hpp" class CompileTask; +class DirectiveSet; // ciEnv // @@ -352,6 +354,7 @@ public: // The compiler task which has created this env. // May be useful to find out compile_id, comp_level, etc. CompileTask* task() { return _task; } + // Handy forwards to the task: int comp_level(); // task()->comp_level() uint compile_id(); // task()->compile_id() @@ -367,9 +370,9 @@ public: ExceptionHandlerTable* handler_table, ImplicitExceptionTable* inc_table, AbstractCompiler* compiler, - int comp_level, bool has_unsafe_access, bool has_wide_vectors, + DirectiveSet* directives, RTMState rtm_state = NoRTM); diff --git a/hotspot/src/share/vm/ci/ciMethod.cpp b/hotspot/src/share/vm/ci/ciMethod.cpp index a0e184fa9ed..3014c7f4a0b 100644 --- a/hotspot/src/share/vm/ci/ciMethod.cpp +++ b/hotspot/src/share/vm/ci/ciMethod.cpp @@ -35,7 +35,6 @@ #include "ci/ciUtilities.hpp" #include "classfile/systemDictionary.hpp" #include "compiler/abstractCompiler.hpp" -#include "compiler/compilerOracle.hpp" #include "compiler/methodLiveness.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/linkResolver.hpp" @@ -1043,51 +1042,6 @@ MethodCounters* ciMethod::ensure_method_counters() { return method_counters; } -// ------------------------------------------------------------------ -// ciMethod::should_inline -// -// Should this method be inlined during compilation? -bool ciMethod::should_inline() { - check_is_loaded(); - VM_ENTRY_MARK; - methodHandle mh(THREAD, get_Method()); - return CompilerOracle::should_inline(mh); -} - -// ------------------------------------------------------------------ -// ciMethod::should_not_inline -// -// Should this method be disallowed from inlining during compilation? -bool ciMethod::should_not_inline() { - check_is_loaded(); - VM_ENTRY_MARK; - methodHandle mh(THREAD, get_Method()); - return CompilerOracle::should_not_inline(mh); -} - -// ------------------------------------------------------------------ -// ciMethod::should_print_assembly -// -// Should the compiler print the generated code for this method? -bool ciMethod::should_print_assembly() { - check_is_loaded(); - VM_ENTRY_MARK; - methodHandle mh(THREAD, get_Method()); - return CompilerOracle::should_print(mh); -} - -// ------------------------------------------------------------------ -// ciMethod::break_at_execute -// -// Should the compiler insert a breakpoint into the generated code -// method? -bool ciMethod::break_at_execute() { - check_is_loaded(); - VM_ENTRY_MARK; - methodHandle mh(THREAD, get_Method()); - return CompilerOracle::should_break_at(mh); -} - // ------------------------------------------------------------------ // ciMethod::has_option // @@ -1101,20 +1055,12 @@ bool ciMethod::has_option(const char* option) { // ------------------------------------------------------------------ // ciMethod::has_option_value // -template -bool ciMethod::has_option_value(const char* option, T& value) { +bool ciMethod::has_option_value(const char* option, double& value) { check_is_loaded(); VM_ENTRY_MARK; methodHandle mh(THREAD, get_Method()); return CompilerOracle::has_option_value(mh, option, value); } -// Explicit instantiation for all OptionTypes supported. -template bool ciMethod::has_option_value(const char* option, intx& value); -template bool ciMethod::has_option_value(const char* option, uintx& value); -template bool ciMethod::has_option_value(const char* option, bool& value); -template bool ciMethod::has_option_value(const char* option, ccstr& value); -template bool ciMethod::has_option_value(const char* option, double& value); - // ------------------------------------------------------------------ // ciMethod::can_be_compiled // diff --git a/hotspot/src/share/vm/ci/ciMethod.hpp b/hotspot/src/share/vm/ci/ciMethod.hpp index d2268703098..743a16463ee 100644 --- a/hotspot/src/share/vm/ci/ciMethod.hpp +++ b/hotspot/src/share/vm/ci/ciMethod.hpp @@ -104,8 +104,6 @@ class ciMethod : public ciMetadata { void load_code(); - void check_is_loaded() const { assert(is_loaded(), "not loaded"); } - bool ensure_method_data(methodHandle h_m); void code_at_put(int bci, Bytecodes::Code code) { @@ -120,6 +118,8 @@ class ciMethod : public ciMetadata { void assert_call_type_ok(int bci); public: + void check_is_loaded() const { assert(is_loaded(), "not loaded"); } + // Basic method information. ciFlags flags() const { check_is_loaded(); return _flags; } ciSymbol* name() const { return _name; } @@ -265,14 +265,8 @@ class ciMethod : public ciMetadata { // Find the proper vtable index to invoke this method. int resolve_vtable_index(ciKlass* caller, ciKlass* receiver); - // Compilation directives - bool should_inline(); - bool should_not_inline(); - bool should_print_assembly(); - bool break_at_execute(); bool has_option(const char *option); - template - bool has_option_value(const char* option, T& value); + bool has_option_value(const char* option, double& value); bool can_be_compiled(); bool can_be_osr_compiled(int entry_bci); void set_not_compilable(const char* reason = NULL); diff --git a/hotspot/src/share/vm/classfile/vmSymbols.cpp b/hotspot/src/share/vm/classfile/vmSymbols.cpp index b70096e9139..9dbdb53a4d3 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.cpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp @@ -417,36 +417,10 @@ int vmIntrinsics::predicates_needed(vmIntrinsics::ID id) { } } -bool vmIntrinsics::is_disabled_by_flags(methodHandle method, methodHandle compilation_context) { +bool vmIntrinsics::is_disabled_by_flags(methodHandle method) { vmIntrinsics::ID id = method->intrinsic_id(); assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); - // Check if the intrinsic corresponding to 'method' has been disabled on - // the command line by using the DisableIntrinsic flag (either globally - // or on a per-method level, see src/share/vm/compiler/abstractCompiler.hpp - // for details). - // Usually, the compilation context is the caller of the method 'method'. - // The only case when for a non-recursive method 'method' the compilation context - // is not the caller of the 'method' (but it is the method itself) is - // java.lang.ref.Referene::get. - // For java.lang.ref.Reference::get, the intrinsic version is used - // instead of the compiled version so that the value in the referent - // field can be registered by the G1 pre-barrier code. The intrinsified - // version of Reference::get also adds a memory barrier to prevent - // commoning reads from the referent field across safepoint since GC - // can change the referent field's value. See Compile::Compile() - // in src/share/vm/opto/compile.cpp or - // GraphBuilder::GraphBuilder() in src/share/vm/c1/c1_GraphBuilder.cpp - // for more details. - ccstr disable_intr = NULL; - if ((DisableIntrinsic[0] != '\0' && strstr(DisableIntrinsic, vmIntrinsics::name_at(id)) != NULL) || - (!compilation_context.is_null() && - CompilerOracle::has_option_value(compilation_context, "DisableIntrinsic", disable_intr) && - strstr(disable_intr, vmIntrinsics::name_at(id)) != NULL) - ) { - return true; - } - // -XX:-InlineNatives disables nearly all intrinsics except the ones listed in // the following switch statement. if (!InlineNatives) { diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index b3ca0886f65..aff2f265d24 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -1402,7 +1402,7 @@ public: // Returns true if a compiler intrinsic is disabled by command-line flags // and false otherwise. - static bool is_disabled_by_flags(methodHandle method, methodHandle compilation_context); + static bool is_disabled_by_flags(methodHandle method); }; #endif // SHARE_VM_CLASSFILE_VMSYMBOLS_HPP diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 0c46606da6a..04f3f314603 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -32,7 +32,7 @@ #include "compiler/abstractCompiler.hpp" #include "compiler/compileBroker.hpp" #include "compiler/compileLog.hpp" -#include "compiler/compilerOracle.hpp" +#include "compiler/compilerDirectives.hpp" #include "compiler/disassembler.hpp" #include "interpreter/bytecode.hpp" #include "oops/methodData.hpp" @@ -582,9 +582,6 @@ nmethod* nmethod::new_native_nmethod(methodHandle method, basic_lock_owner_sp_offset, basic_lock_sp_offset, oop_maps); NOT_PRODUCT(if (nm != NULL) native_nmethod_stats.note_native_nmethod(nm)); - if ((PrintAssembly || CompilerOracle::should_print(method)) && nm != NULL) { - Disassembler::decode(nm); - } } // verify nmethod debug_only(if (nm) nm->verify();) // might block @@ -666,9 +663,6 @@ nmethod* nmethod::new_nmethod(methodHandle method, } } NOT_PRODUCT(if (nm != NULL) note_java_nmethod(nm)); - if (PrintAssembly || CompilerOracle::has_option_string(method, "PrintAssembly")) { - Disassembler::decode(nm); - } } } // Do verification and logging outside CodeCache_lock. @@ -908,13 +902,6 @@ nmethod::nmethod( _method->is_static() == (entry_point() == _verified_entry_point), " entry points must be same for static methods and vice versa"); } - - bool printnmethods = PrintNMethods || PrintNMethodsAtLevel == _comp_level - || CompilerOracle::should_print(_method) - || CompilerOracle::has_option_string(_method, "PrintNMethods"); - if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) { - print_nmethod(printnmethods); - } } // Print a short set of xml attributes to identify this nmethod. The diff --git a/hotspot/src/share/vm/compiler/abstractCompiler.hpp b/hotspot/src/share/vm/compiler/abstractCompiler.hpp index 96dfbd45b58..1c5304f6475 100644 --- a/hotspot/src/share/vm/compiler/abstractCompiler.hpp +++ b/hotspot/src/share/vm/compiler/abstractCompiler.hpp @@ -26,6 +26,7 @@ #define SHARE_VM_COMPILER_ABSTRACTCOMPILER_HPP #include "ci/compilerInterface.hpp" +#include "compiler/compilerDirectives.hpp" typedef void (*initializer)(void); @@ -114,36 +115,33 @@ class AbstractCompiler : public CHeapObj { // Determine if the current compiler provides an intrinsic // for method 'method'. An intrinsic is available if: - // - the intrinsic is enabled (by using the appropriate command-line flag) and + // - the intrinsic is enabled (by using the appropriate command-line flag, + // the command-line compile ommand, or a compiler directive) // - the platform on which the VM is running supports the intrinsic // (i.e., the platform provides the instructions necessary for the compiler // to generate the intrinsic code). // - // The second parameter, 'compilation_context', is needed to implement functionality - // related to the DisableIntrinsic command-line flag. The DisableIntrinsic flag can - // be used to prohibit the compilers to use an intrinsic. There are three ways to - // disable an intrinsic using the DisableIntrinsic flag: + // The directive provides the compilation context and includes pre-evaluated values + // dependent on VM flags, compile commands, and compiler directives. // - // (1) -XX:DisableIntrinsic=_hashCode,_getClass - // Disables intrinsification of _hashCode and _getClass globally - // (i.e., the intrinsified version the methods will not be used at all). - // (2) -XX:CompileCommand=option,aClass::aMethod,ccstr,DisableIntrinsic,_hashCode - // Disables intrinsification of _hashCode if it is called from - // aClass::aMethod (but not for any other call site of _hashCode) - // (3) -XX:CompileCommand=option,java.lang.ref.Reference::get,ccstr,DisableIntrinsic,_Reference_get - // Some methods are not compiled by C2. Instead, the C2 compiler - // returns directly the intrinsified version of these methods. - // The command above forces C2 to compile _Reference_get, but - // allows using the intrinsified version of _Reference_get at all - // other call sites. - // - // From the modes above, (1) disable intrinsics globally, (2) and (3) - // disable intrinsics on a per-method basis. In cases (2) and (3) the - // compilation context is aClass::aMethod and java.lang.ref.Reference::get, - // respectively. - virtual bool is_intrinsic_available(methodHandle method, methodHandle compilation_context) { + // Usually, the compilation context is the caller of the method 'method'. + // The only case when for a non-recursive method 'method' the compilation context + // is not the caller of the 'method' (but it is the method itself) is + // java.lang.ref.Referene::get. + // For java.lang.ref.Reference::get, the intrinsic version is used + // instead of the compiled version so that the value in the referent + // field can be registered by the G1 pre-barrier code. The intrinsified + // version of Reference::get also adds a memory barrier to prevent + // commoning reads from the referent field across safepoint since GC + // can change the referent field's value. See Compile::Compile() + // in src/share/vm/opto/compile.cpp or + // GraphBuilder::GraphBuilder() in src/share/vm/c1/c1_GraphBuilder.cpp + // for more details. + + virtual bool is_intrinsic_available(methodHandle method, DirectiveSet* directive) { return is_intrinsic_supported(method) && - !vmIntrinsics::is_disabled_by_flags(method, compilation_context); + !directive->is_intrinsic_disabled(method) && + !vmIntrinsics::is_disabled_by_flags(method); } // Determines if an intrinsic is supported by the compiler, that is, @@ -176,7 +174,7 @@ class AbstractCompiler : public CHeapObj { void set_state (int state); void set_shut_down () { set_state(shut_down); } // Compilation entry point for methods - virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci) { + virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive) { ShouldNotReachHere(); } diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 89d969e4f94..f00add3d203 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -29,6 +29,7 @@ #include "compiler/compileBroker.hpp" #include "compiler/compileLog.hpp" #include "compiler/compilerOracle.hpp" +#include "compiler/directivesParser.hpp" #include "interpreter/linkResolver.hpp" #include "memory/allocation.inline.hpp" #include "oops/methodData.hpp" @@ -202,10 +203,22 @@ class CompilationLog : public StringEventLog { static CompilationLog* _compilation_log = NULL; -void compileBroker_init() { +bool compileBroker_init() { if (LogEvents) { _compilation_log = new CompilationLog(); } + + // init directives stack, adding default directive + DirectivesStack::init(); + + if (DirectivesParser::has_file()) { + return DirectivesParser::parse_from_flag(); + } else if (PrintCompilerDirectives) { + // Print default directive even when no other was added + DirectivesStack::print(tty); + } + + return true; } CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) { @@ -1180,11 +1193,15 @@ bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci, return true; } + // Breaking the abstraction - directives are only used inside a compilation otherwise. + DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, comp); + bool excluded = directive->ExcludeOption; + DirectivesStack::release(directive); + // The method may be explicitly excluded by the user. - bool quietly; double scale; - if (CompilerOracle::should_exclude(method, quietly) - || (CompilerOracle::has_option_value(method, "CompileThresholdScaling", scale) && scale == 0)) { + if (excluded || (CompilerOracle::has_option_value(method, "CompileThresholdScaling", scale) && scale == 0)) { + bool quietly = CompilerOracle::should_exclude_quietly(); if (!quietly) { // This does not happen quietly... ResourceMark rm; @@ -1194,7 +1211,7 @@ bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci, method->print_short_name(tty); tty->cr(); } - method->set_not_compilable(CompLevel_all, !quietly, "excluded by CompileCommand"); + method->set_not_compilable(comp_level, !quietly, "excluded by CompileCommand"); } return false; @@ -1357,7 +1374,6 @@ bool CompileBroker::init_compiler_runtime() { ThreadInVMfromNative tv(thread); ResetNoHandleMark rnhm; - if (!comp->is_shark()) { // Perform per-thread and global initializations comp->initialize(); @@ -1629,6 +1645,10 @@ void CompileBroker::post_compile(CompilerThread* thread, CompileTask* task, Even } } +int DirectivesStack::_depth = 0; +CompilerDirectives* DirectivesStack::_top = NULL; +CompilerDirectives* DirectivesStack::_bottom = NULL; + // ------------------------------------------------------------------ // CompileBroker::invoke_compiler_on_method // @@ -1655,16 +1675,20 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { bool should_log = (thread->log() != NULL); bool should_break = false; int task_level = task->comp_level(); + + // Look up matching directives + DirectiveSet* directive = DirectivesStack::getMatchingDirective(task->method(), compiler(task_level)); + + should_break = directive->BreakAtExecuteOption || task->check_break_at_flags(); + if (should_log && !directive->LogOption) { + should_log = false; + } { // create the handle inside it's own block so it can't // accidentally be referenced once the thread transitions to // native. The NoHandleMark before the transition should catch // any cases where this occurs in the future. methodHandle method(thread, task->method()); - should_break = check_break_at(method, compile_id, is_osr); - if (should_log && !CompilerOracle::should_log(method)) { - should_log = false; - } assert(!method->is_native(), "no longer compile natives"); // Save information about this method in case of failure. @@ -1732,7 +1756,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { locker.wait(Mutex::_no_safepoint_check_flag); } } - comp->compile_method(&ci_env, target, osr_bci); + comp->compile_method(&ci_env, target, osr_bci, directive); } if (!ci_env.failing() && task->code() == NULL) { @@ -1762,6 +1786,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { post_compile(thread, task, event, !ci_env.failing(), &ci_env); } + DirectivesStack::release(directive); pop_jni_handle_block(); methodHandle method(thread, task->method()); @@ -1947,21 +1972,6 @@ void CompileBroker::pop_jni_handle_block() { JNIHandleBlock::release_block(compile_handles, thread); // may block } - -// ------------------------------------------------------------------ -// CompileBroker::check_break_at -// -// Should the compilation break at the current compilation. -bool CompileBroker::check_break_at(methodHandle method, int compile_id, bool is_osr) { - if (CICountOSR && is_osr && (compile_id == CIBreakAtOSR)) { - return true; - } else if( CompilerOracle::should_break_at(method) ) { // break when compiling - return true; - } else { - return (compile_id == CIBreakAt); - } -} - // ------------------------------------------------------------------ // CompileBroker::collect_statistics // @@ -2232,3 +2242,4 @@ void CompileBroker::print_compiler_threads_on(outputStream* st) { st->cr(); #endif } + diff --git a/hotspot/src/share/vm/compiler/compileBroker.hpp b/hotspot/src/share/vm/compiler/compileBroker.hpp index 3363db9d25c..b469aebd769 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.hpp +++ b/hotspot/src/share/vm/compiler/compileBroker.hpp @@ -28,8 +28,10 @@ #include "ci/compilerInterface.hpp" #include "compiler/abstractCompiler.hpp" #include "compiler/compileTask.hpp" +#include "compiler/compilerDirectives.hpp" #include "runtime/perfData.hpp" #include "trace/tracing.hpp" +#include "utilities/stack.hpp" class nmethod; class nmethodLocker; @@ -129,13 +131,12 @@ public: ~CompileTaskWrapper(); }; - // Compilation // // The broker for all compilation requests. class CompileBroker: AllStatic { friend class Threads; - friend class CompileTaskWrapper; + friend class CompileTaskWrapper; public: enum { @@ -238,7 +239,6 @@ class CompileBroker: AllStatic { static void set_last_compile(CompilerThread *thread, methodHandle method, bool is_osr, int comp_level); static void push_jni_handle_block(); static void pop_jni_handle_block(); - static bool check_break_at(methodHandle method, int compile_id, bool is_osr); static void collect_statistics(CompilerThread* thread, elapsedTimer time, CompileTask* task); static void compile_method_base(methodHandle method, @@ -253,7 +253,11 @@ class CompileBroker: AllStatic { static bool init_compiler_runtime(); static void shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread); - public: +public: + + static DirectivesStack* dirstack(); + static void set_dirstack(DirectivesStack* stack); + enum { // The entry bci used for non-OSR compilations. standard_entry_bci = InvocationEntryBci @@ -267,6 +271,7 @@ class CompileBroker: AllStatic { static bool compilation_is_in_queue(methodHandle method); static void print_compile_queues(outputStream* st); + static void print_directives(outputStream* st); static int queue_size(int comp_level) { CompileQueue *q = compile_queue(comp_level); return q != NULL ? q->size() : 0; diff --git a/hotspot/src/share/vm/compiler/compileTask.cpp b/hotspot/src/share/vm/compiler/compileTask.cpp index 0dcc95d23c8..a01b960899c 100644 --- a/hotspot/src/share/vm/compiler/compileTask.cpp +++ b/hotspot/src/share/vm/compiler/compileTask.cpp @@ -26,6 +26,7 @@ #include "compiler/compileTask.hpp" #include "compiler/compileLog.hpp" #include "compiler/compileBroker.hpp" +#include "compiler/compilerDirectives.hpp" CompileTask* CompileTask::_task_free_list = NULL; #ifdef ASSERT @@ -371,6 +372,19 @@ void CompileTask::log_task_done(CompileLog* log) { log->mark_file_end(); } +// ------------------------------------------------------------------ +// CompileTask::check_break_at_flags +bool CompileTask::check_break_at_flags() { + int compile_id = this->_compile_id; + bool is_osr = (_osr_bci != CompileBroker::standard_entry_bci); + + if (CICountOSR && is_osr && (compile_id == CIBreakAtOSR)) { + return true; + } else { + return (compile_id == CIBreakAt); + } +} + // ------------------------------------------------------------------ // CompileTask::print_inlining void CompileTask::print_inlining_inner(outputStream* st, ciMethod* method, int inline_level, int bci, const char* msg) { diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.cpp b/hotspot/src/share/vm/compiler/compilerDirectives.cpp new file mode 100644 index 00000000000..8421bcc16db --- /dev/null +++ b/hotspot/src/share/vm/compiler/compilerDirectives.cpp @@ -0,0 +1,502 @@ +/* + * Copyright (c) 1998, 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. + * + */ + +#include "precompiled.hpp" +#include "ci/ciMethod.hpp" +#include "ci/ciUtilities.hpp" +#include "compiler/abstractCompiler.hpp" +#include "compiler/compilerDirectives.hpp" +#include "compiler/compilerOracle.hpp" + +CompilerDirectives::CompilerDirectives() :_match(NULL), _next(NULL), _ref_count(0) { + _c1_store = new DirectiveSet(this); + _c2_store = new DirectiveSet(this); +}; + +CompilerDirectives::~CompilerDirectives() { + if (_c1_store != NULL) { + delete _c1_store; + } + if (_c2_store != NULL) { + delete _c2_store; + } + + // remove all linked method matchers + BasicMatcher* tmp = _match; + while (tmp != NULL) { + BasicMatcher* next = tmp->next(); + delete tmp; + tmp = next; + } +} + +void CompilerDirectives::print(outputStream* st) { + assert(DirectivesStack_lock->owned_by_self(), ""); + if (_match != NULL) { + st->cr(); + st->print("Directive:"); + if (is_default_directive()) { + st->print_cr(" (default)"); + } else { + st->cr(); + } + st->print(" matching: "); + _match->print(st); + BasicMatcher* tmp = _match->next(); + while (tmp != NULL) { + st->print(", "); + tmp->print(st); + tmp = tmp->next(); + } + st->cr(); + } else { + assert(0, "There should always be a match"); + } + + if (_c1_store != NULL) { + st->print_cr(" c1 directives:"); + _c1_store->print(st); + } + if (_c2_store != NULL) { + st->cr(); + st->print_cr(" c2 directives:"); + _c2_store->print(st); + } + //--- +} + +void CompilerDirectives::finalize() { + if (_c1_store != NULL) { + _c1_store->finalize(); + } + if (_c2_store != NULL) { + _c2_store->finalize(); + } +} + +void DirectiveSet::finalize() { + // if any flag has been modified - set directive as enabled + // unless it already has been explicitly set. + if (!_modified[EnableIndex]) { + if (_inlinematchers != NULL) { + EnableOption = true; + return; + } + int i; + for (i = 0; i < number_of_flags; i++) { + if (_modified[i]) { + EnableOption = true; + return; + } + } + } +} + +CompilerDirectives* CompilerDirectives::next() { + return _next; +} + +bool CompilerDirectives::match(methodHandle method) { + if (is_default_directive()) { + return true; + } + if (method == NULL) { + return false; + } + if (_match->match(method)) { + return true; + } + return false; +} + +bool CompilerDirectives::add_match(char* str, const char*& error_msg) { + BasicMatcher* bm = BasicMatcher::parse_method_pattern(str, error_msg); + if (bm == NULL) { + assert(error_msg != NULL, "Must have error message"); + return false; + } else { + bm->set_next(_match); + _match = bm; + return true; + } +} + +void CompilerDirectives::inc_refcount() { + assert(DirectivesStack_lock->owned_by_self(), ""); + _ref_count++; +} + +void CompilerDirectives::dec_refcount() { + assert(DirectivesStack_lock->owned_by_self(), ""); + _ref_count--; +} + +int CompilerDirectives::refcount() { + assert(DirectivesStack_lock->owned_by_self(), ""); + return _ref_count; +} + +DirectiveSet* CompilerDirectives::get_for(AbstractCompiler *comp) { + assert(DirectivesStack_lock->owned_by_self(), ""); + inc_refcount(); // The compiling thread is responsible to decrement this when finished. + if (comp == NULL) { // Xint + return _c1_store; + } else if (comp->is_c2()) { + return _c2_store; + } else if (comp->is_c1()) { + return _c1_store; + } else if (comp->is_shark()) { + return NULL; + } else if (comp->is_jvmci()) { + return NULL; + } + ShouldNotReachHere(); + return NULL; +} + +DirectiveSet::DirectiveSet(CompilerDirectives* d) :_inlinematchers(NULL), _directive(d) { +#define init_defaults_definition(name, type, dvalue, compiler) this->name##Option = dvalue; + compilerdirectives_common_flags(init_defaults_definition) + compilerdirectives_c2_flags(init_defaults_definition) + compilerdirectives_c1_flags(init_defaults_definition) + memset(_modified, 0, sizeof _modified); +} + +DirectiveSet::~DirectiveSet() { + // remove all linked methodmatchers + InlineMatcher* tmp = _inlinematchers; + while (tmp != NULL) { + InlineMatcher* next = tmp->next(); + delete tmp; + tmp = next; + } + + // Free if modified, otherwise it just points to the global vm flag value + // or to the Compile command option + if (_modified[DisableIntrinsicIndex]) { + assert(this->DisableIntrinsicOption != NULL, ""); + FREE_C_HEAP_ARRAY(char, (void *)this->DisableIntrinsicOption); + } +} + +// Backward compatibility for CompileCommands +// Breaks the abstraction and causes lots of extra complexity +// - if some option is changed we need to copy directiveset since it no longer can be shared +// - Need to free copy after use +// - Requires a modified bit so we don't overwrite options that is set by directives + +DirectiveSet* DirectiveSet::compilecommand_compatibility_init(methodHandle method) { + // Early bail out - checking all options is expensive - we rely on them not being used + // Only set a flag if it has not been modified and value changes. + // Only copy set if a flag needs to be set + if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::has_any_option()) { + DirectiveSet* set = DirectiveSet::clone(this); + + bool changed = false; // Track if we actually change anything + + // All CompileCommands are not equal so this gets a bit verbose + // When CompileCommands have been refactored less clutter will remain. + if (CompilerOracle::should_break_at(method)) { + if (!_modified[BreakAtCompileIndex]) { + set->BreakAtCompileOption = true; + changed = true; + } + if (!_modified[BreakAtExecuteIndex]) { + set->BreakAtExecuteOption = true; + changed = true; + } + } + if (CompilerOracle::should_log(method)) { + if (!_modified[LogIndex]) { + set->LogOption = true; + changed = true; + } + } + if (CompilerOracle::should_print(method)) { + if (!_modified[PrintAssemblyIndex]) { + set->PrintAssemblyOption = true; + changed = true; + } + } + // Exclude as in should not compile == Enabled + if (CompilerOracle::should_exclude(method)) { + if (!_modified[ExcludeIndex]) { + set->ExcludeOption = true; + changed = true; + } + } + + // inline and dontinline (including exclude) are implemented in the directiveset accessors +#define init_default_cc(name, type, dvalue, cc_flag) { type v; if (!_modified[name##Index] && CompilerOracle::has_option_value(method, #cc_flag, v) && v != this->name##Option) { set->name##Option = v; changed = true;} } + compilerdirectives_common_flags(init_default_cc) + compilerdirectives_c2_flags(init_default_cc) + compilerdirectives_c1_flags(init_default_cc) + + if (!changed) { + // We didn't actually update anything, discard. + delete set; + } else { + // We are returning a (parentless) copy. The originals parent don't need to account for this. + DirectivesStack::release(this); + return set; + } + } + // Nothing changed + return this; +} + +CompilerDirectives* DirectiveSet::directive() { + assert(_directive != NULL, "Must have been initialized"); + return _directive; +} + +bool DirectiveSet::matches_inline(methodHandle method, int inline_action) { + if (_inlinematchers != NULL) { + if (_inlinematchers->match(method, InlineMatcher::force_inline)) { + return true; + } + } + return false; +} + +bool DirectiveSet::should_inline(ciMethod* inlinee) { + inlinee->check_is_loaded(); + VM_ENTRY_MARK; + methodHandle mh(THREAD, inlinee->get_Method()); + + if (matches_inline(mh, InlineMatcher::force_inline)) { + return true; + } + if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::should_inline(mh)) { + return true; + } + return false; +} + +bool DirectiveSet::should_not_inline(ciMethod* inlinee) { + inlinee->check_is_loaded(); + VM_ENTRY_MARK; + methodHandle mh(THREAD, inlinee->get_Method()); + + if (matches_inline(mh, InlineMatcher::dont_inline)) { + return true; + } + if (!CompilerDirectivesIgnoreCompileCommandsOption && CompilerOracle::should_not_inline(mh)) { + return true; + } + return false; +} + +bool DirectiveSet::parse_and_add_inline(char* str, const char*& error_msg) { + InlineMatcher* m = InlineMatcher::parse_inline_pattern(str, error_msg); + if (m != NULL) { + // add matcher last in chain - the order is significant + append_inline(m); + return true; + } else { + assert(error_msg != NULL, "Error message must be set"); + return false; + } +} + +void DirectiveSet::append_inline(InlineMatcher* m) { + if (_inlinematchers == NULL) { + _inlinematchers = m; + return; + } + InlineMatcher* tmp = _inlinematchers; + while (tmp->next() != NULL) { + tmp = tmp->next(); + } + tmp->set_next(m); +} + +void DirectiveSet::print_inline(outputStream* st) { + if (_inlinematchers == NULL) { + st->print_cr(" inline: -"); + } else { + st->print(" inline: "); + _inlinematchers->print(st); + InlineMatcher* tmp = _inlinematchers->next(); + while (tmp != NULL) { + st->print(", "); + tmp->print(st); + tmp = tmp->next(); + } + st->cr(); + } +} + +bool DirectiveSet::is_intrinsic_disabled(methodHandle method) { + vmIntrinsics::ID id = method->intrinsic_id(); + assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); + + ccstr disable_intr = DisableIntrinsicOption; + return ((disable_intr != '\0') && strstr(disable_intr, vmIntrinsics::name_at(id)) != NULL); +} + +DirectiveSet* DirectiveSet::clone(DirectiveSet const* src) { + DirectiveSet* set = new DirectiveSet(NULL); + memcpy(set->_modified, src->_modified, sizeof(src->_modified)); + + InlineMatcher* tmp = src->_inlinematchers; + while (tmp != NULL) { + set->append_inline(tmp->clone()); + tmp = tmp->next(); + } + + #define copy_members_definition(name, type, dvalue, cc_flag) set->name##Option = src->name##Option; + compilerdirectives_common_flags(copy_members_definition) + compilerdirectives_c2_flags(copy_members_definition) + compilerdirectives_c1_flags(copy_members_definition) + + // Must duplicate ccstr option if it was modified, otherwise it is global. + if (src->_modified[DisableIntrinsicIndex]) { + assert(src->DisableIntrinsicOption != NULL, ""); + size_t len = strlen(src->DisableIntrinsicOption) + 1; + char* s = NEW_C_HEAP_ARRAY(char, len, mtCompiler); + strncpy(s, src->DisableIntrinsicOption, len); + assert(s[len-1] == '\0', ""); + set->DisableIntrinsicOption = s; + } + return set; +} + +// Create a new dirstack and push a default directive +void DirectivesStack::init() { + CompilerDirectives* _default_directives = new CompilerDirectives(); + char str[] = "*.*"; + const char* error_msg = NULL; + _default_directives->add_match(str, error_msg); +#ifdef COMPILER1 + _default_directives->_c1_store->EnableOption = true; +#endif +#ifdef COMPILER2 + _default_directives->_c2_store->EnableOption = true; +#endif + assert(error_msg == NULL, "Must succeed."); + push(_default_directives); +} + +DirectiveSet* DirectivesStack::getDefaultDirective(AbstractCompiler* comp) { + MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag); + + assert(_bottom != NULL, "Must never be empty"); + return _bottom->get_for(comp); +} + +void DirectivesStack::push(CompilerDirectives* directive) { + MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag); + + directive->inc_refcount(); + if (_top == NULL) { + assert(_bottom == NULL, "There can only be one default directive"); + _bottom = directive; // default directive, can never be removed. + } + + directive->set_next(_top); + _top = directive; + _depth++; +} + +void DirectivesStack::pop() { + MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag); + pop_inner(); +} + +void DirectivesStack::pop_inner() { + assert(DirectivesStack_lock->owned_by_self(), ""); + + if (_top->next() == NULL) { + return; // Do nothing - don't allow an empty stack + } + CompilerDirectives* tmp = _top; + _top = _top->next(); + _depth--; + + DirectivesStack::release(tmp); +} + +void DirectivesStack::clear() { + // holding the lock during the whole operation ensuring consistent result + MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag); + while (_top->next() != NULL) { + pop_inner(); + } +} + +void DirectivesStack::print(outputStream* st) { + MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag); + CompilerDirectives* tmp = _top; + while (tmp != NULL) { + tmp->print(st); + tmp = tmp->next(); + st->cr(); + } +} + +void DirectivesStack::release(DirectiveSet* set) { + MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag); + if (set->is_exclusive_copy()) { + // Old CompilecCmmands forced us to create an exclusive copy + delete set; + } else { + assert(set->directive() != NULL, ""); + release(set->directive()); + } +} + + +void DirectivesStack::release(CompilerDirectives* dir) { + assert(DirectivesStack_lock->owned_by_self(), ""); + dir->dec_refcount(); + if (dir->refcount() == 0) { + delete dir; + } +} + +DirectiveSet* DirectivesStack::getMatchingDirective(methodHandle method, AbstractCompiler *comp) { + assert(_depth > 0, "Must never be empty"); + CompilerDirectives* dir = _top; + assert(dir != NULL, "Must be initialized"); + + DirectiveSet* match = NULL; + { + MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag); + while (dir != NULL) { + if (dir->is_default_directive() || dir->match(method)) { + match = dir->get_for(comp); + if (match->EnableOption) { + // The directiveSet for this compile is also enabled -> success + break; + } + } + dir = dir->next(); + } + } + + guarantee(match != NULL, "There should always be a default directive that matches"); + // Check for legacy compile commands update, without DirectivesStack_lock + return match->compilecommand_compatibility_init(method); +} diff --git a/hotspot/src/share/vm/compiler/compilerDirectives.hpp b/hotspot/src/share/vm/compiler/compilerDirectives.hpp new file mode 100644 index 00000000000..5b39868b852 --- /dev/null +++ b/hotspot/src/share/vm/compiler/compilerDirectives.hpp @@ -0,0 +1,186 @@ +/* + * Copyright (c) 1998, 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. + * + */ + +#ifndef SHARE_VM_COMPILER_COMPILERDIRECTIVES_HPP +#define SHARE_VM_COMPILER_COMPILERDIRECTIVES_HPP + +#include "ci/ciMetadata.hpp" +#include "ci/ciMethod.hpp" +#include "ci/ciUtilities.hpp" +#include "compiler/methodMatcher.hpp" +#include "compiler/compilerOracle.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/exceptions.hpp" + + // Directives flag name, type, default value, compile command name + #define compilerdirectives_common_flags(cflags) \ + cflags(Enable, bool, false, X) \ + cflags(Exclude, bool, false, X) \ + cflags(BreakAtExecute, bool, false, X) \ + cflags(BreakAtCompile, bool, false, X) \ + cflags(Log, bool, false, X) \ + cflags(PrintAssembly, bool, PrintAssembly, PrintAssembly) \ + cflags(PrintInlining, bool, PrintInlining, PrintInlining) \ + cflags(PrintNMethods, bool, PrintNMethods, PrintNMethods) \ + cflags(ReplayInline, bool, false, ReplayInline) \ + cflags(DumpReplay, bool, false, DumpReplay) \ + cflags(DumpInline, bool, false, DumpInline) \ + cflags(CompilerDirectivesIgnoreCompileCommands, bool, CompilerDirectivesIgnoreCompileCommands, X) \ + cflags(DisableIntrinsic, ccstr, DisableIntrinsic, DisableIntrinsic) + +#ifdef COMPILER1 + #define compilerdirectives_c1_flags(cflags) +#else + #define compilerdirectives_c1_flags(cflags) +#endif + +#ifdef COMPILER2 + #define compilerdirectives_c2_flags(cflags) \ + cflags(BlockLayoutByFrequency, bool, BlockLayoutByFrequency, BlockLayoutByFrequency) \ + cflags(PrintOptoAssembly, bool, PrintOptoAssembly, PrintOptoAssembly) \ + cflags(PrintIntrinsics, bool, PrintIntrinsics, PrintIntrinsics) \ + cflags(TraceOptoPipelining, bool, false, TraceOptoPipelining) \ + cflags(TraceOptoOutput, bool, false, TraceOptoOutput) \ + cflags(TraceSpilling, bool, TraceSpilling, TraceSpilling) \ + cflags(Vectorize, bool, false, Vectorize) \ + cflags(VectorizeDebug, bool, false, VectorizeDebug) \ + cflags(CloneMapDebug, bool, false, CloneMapDebug) \ + cflags(DoReserveCopyInSuperWordDebug, bool, false, DoReserveCopyInSuperWordDebug) \ + cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel) \ + cflags(MaxNodeLimit, intx, MaxNodeLimit, MaxNodeLimit) +#else + #define compilerdirectives_c2_flags(cflags) +#endif + +class CompilerDirectives; +class DirectiveSet; + +class DirectivesStack : AllStatic { +private: + static CompilerDirectives* _top; + static CompilerDirectives* _bottom; + static int _depth; + + static void pop_inner(); // no lock version of pop +public: + static void init(); + static DirectiveSet* getMatchingDirective(methodHandle mh, AbstractCompiler* comp); + static DirectiveSet* getDefaultDirective(AbstractCompiler* comp); + static void push(CompilerDirectives* directive); + static void pop(); + static void clear(); + static void print(outputStream* st); + static void release(DirectiveSet* set); + static void release(CompilerDirectives* dir); +}; + +class DirectiveSet : public CHeapObj { +private: + InlineMatcher* _inlinematchers; + CompilerDirectives* _directive; + +public: + DirectiveSet(CompilerDirectives* directive); + ~DirectiveSet(); + CompilerDirectives* directive(); + bool parse_and_add_inline(char* str, const char*& error_msg); + void append_inline(InlineMatcher* m); + bool should_inline(ciMethod* inlinee); + bool should_not_inline(ciMethod* inlinee); + void print_inline(outputStream* st); + DirectiveSet* compilecommand_compatibility_init(methodHandle method); + bool is_exclusive_copy() { return _directive == NULL; } + bool matches_inline(methodHandle method, int inline_action); + static DirectiveSet* clone(DirectiveSet const* src); + bool is_intrinsic_disabled(methodHandle method); + void finalize(); + + typedef enum { +#define enum_of_flags(name, type, dvalue, cc_flag) name##Index, + compilerdirectives_common_flags(enum_of_flags) + compilerdirectives_c2_flags(enum_of_flags) + compilerdirectives_c1_flags(enum_of_flags) + number_of_flags + } flags; + + bool _modified[number_of_flags]; + +#define flag_store_definition(name, type, dvalue, cc_flag) type name##Option; + compilerdirectives_common_flags(flag_store_definition) + compilerdirectives_c2_flags(flag_store_definition) + compilerdirectives_c1_flags(flag_store_definition) + +// Casting to get the same function signature for all setters. Used from parser. +#define set_function_definition(name, type, dvalue, cc_flag) void set_##name(void* value) { type val = *(type*)value; name##Option = val; _modified[name##Index] = 1; } + compilerdirectives_common_flags(set_function_definition) + compilerdirectives_c2_flags(set_function_definition) + compilerdirectives_c1_flags(set_function_definition) + + void print_intx(outputStream* st, ccstr n, intx v, bool mod) { if (mod) { st->print("%s:" INTX_FORMAT " ", n, v); } } + void print_bool(outputStream* st, ccstr n, bool v, bool mod) { if (mod) { st->print("%s:%s ", n, v ? "true" : "false"); } } + void print_double(outputStream* st, ccstr n, double v, bool mod) { if (mod) { st->print("%s:%f ", n, v); } } + void print_ccstr(outputStream* st, ccstr n, ccstr v, bool mod) { if (mod) { st->print("%s:%s ", n, v); } } + +void print(outputStream* st) { + print_inline(st); + st->print(" "); +#define print_function_definition(name, type, dvalue, cc_flag) print_##type(st, #name, this->name##Option, true);//(bool)_modified[name##Index]); + compilerdirectives_common_flags(print_function_definition) + compilerdirectives_c2_flags(print_function_definition) + compilerdirectives_c1_flags(print_function_definition) + st->cr(); + } +}; + +class CompilerDirectives : public CHeapObj { +private: + CompilerDirectives* _next; + BasicMatcher* _match; + int _ref_count; + +public: + + CompilerDirectives(); + ~CompilerDirectives(); + + CompilerDirectives* next(); + void set_next(CompilerDirectives* next) {_next = next; } + + bool match(methodHandle method); + BasicMatcher* match() { return _match; } + bool add_match(char* str, const char*& error_msg); + DirectiveSet* get_for(AbstractCompiler *comp); + void print(outputStream* st); + bool is_default_directive() { return _next == NULL; } + void finalize(); + + void inc_refcount(); + void dec_refcount(); + int refcount(); + + DirectiveSet* _c1_store; + DirectiveSet* _c2_store; +}; + +#endif // SHARE_VM_COMPILER_COMPILERDIRECTIVES_HPP diff --git a/hotspot/src/share/vm/compiler/compilerOracle.cpp b/hotspot/src/share/vm/compiler/compilerOracle.cpp index 4e90f6ad679..471249305af 100644 --- a/hotspot/src/share/vm/compiler/compilerOracle.cpp +++ b/hotspot/src/share/vm/compiler/compilerOracle.cpp @@ -106,6 +106,7 @@ class TypedMethodOptionMatcher; static BasicMatcher* lists[OracleCommandCount] = { 0, }; static TypedMethodOptionMatcher* option_list = NULL; +static bool any_set = false; class TypedMethodOptionMatcher : public MethodMatcher { private: @@ -292,6 +293,7 @@ static void add_option_string(TypedMethodOptionMatcher* matcher, matcher->init(option, get_type_for(), option_list); matcher->set_value(value); option_list = matcher; + any_set = true; return; } @@ -308,7 +310,9 @@ static void add_predicate(OracleCommand command, BasicMatcher* bm) { } bm->set_next(lists[command]); lists[command] = bm; - + if ((command != DontInlineCommand) && (command != InlineCommand)) { + any_set = true; + } return; } @@ -324,6 +328,10 @@ bool CompilerOracle::has_option_value(methodHandle method, const char* option, T return false; } +bool CompilerOracle::has_any_option() { + return any_set; +} + // Explicit instantiation for all OptionTypes supported. template bool CompilerOracle::has_option_value(methodHandle method, const char* option, intx& value); template bool CompilerOracle::has_option_value(methodHandle method, const char* option, uintx& value); @@ -337,15 +345,10 @@ bool CompilerOracle::has_option_string(methodHandle method, const char* option) return value; } -bool CompilerOracle::should_exclude(methodHandle method, bool& quietly) { - quietly = true; - if (lists[ExcludeCommand] != NULL) { - if (lists[ExcludeCommand]->match(method)) { - quietly = _quiet; - return true; - } +bool CompilerOracle::should_exclude(methodHandle method) { + if (check_predicate(ExcludeCommand, method)) { + return true; } - if (lists[CompileOnlyCommand] != NULL) { return !lists[CompileOnlyCommand]->match(method); } @@ -356,8 +359,6 @@ bool CompilerOracle::should_inline(methodHandle method) { return (check_predicate(InlineCommand, method)); } -// Check both DontInlineCommand and ExcludeCommand here -// - consistent behavior for all compilers bool CompilerOracle::should_not_inline(methodHandle method) { return check_predicate(DontInlineCommand, method) || check_predicate(ExcludeCommand, method); } diff --git a/hotspot/src/share/vm/compiler/compilerOracle.hpp b/hotspot/src/share/vm/compiler/compilerOracle.hpp index e369e84e888..454fc6317d4 100644 --- a/hotspot/src/share/vm/compiler/compilerOracle.hpp +++ b/hotspot/src/share/vm/compiler/compilerOracle.hpp @@ -46,7 +46,8 @@ class CompilerOracle : AllStatic { static void parse_from_file(); // Tells whether we to exclude compilation of method - static bool should_exclude(methodHandle method, bool& quietly); + static bool should_exclude(methodHandle method); + static bool should_exclude_quietly() { return _quiet; } // Tells whether we want to inline this method static bool should_inline(methodHandle method); @@ -71,6 +72,9 @@ class CompilerOracle : AllStatic { template static bool has_option_value(methodHandle method, const char* option, T& value); + // Fast check if there is any option available that compile control needs to know about + static bool has_any_option(); + // Reads from string instead of file static void parse_from_string(const char* command_string, void (*parser)(char*)); diff --git a/hotspot/src/share/vm/compiler/directivesParser.cpp b/hotspot/src/share/vm/compiler/directivesParser.cpp new file mode 100644 index 00000000000..5b2fa5c6a6f --- /dev/null +++ b/hotspot/src/share/vm/compiler/directivesParser.cpp @@ -0,0 +1,726 @@ +/* + * 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 "compiler/compileBroker.hpp" +#include "compiler/directivesParser.hpp" +#include "memory/allocation.inline.hpp" +#include "runtime/os.hpp" +#include + +void DirectivesParser::push_tmp(CompilerDirectives* dir) { + dir->set_next(_tmp_top); + _tmp_top = dir; +} + +CompilerDirectives* DirectivesParser::pop_tmp() { + if (_tmp_top == NULL) { + return NULL; + } + CompilerDirectives* tmp = _tmp_top; + _tmp_top = _tmp_top->next(); + tmp->set_next(NULL); + return tmp; +} + +bool DirectivesParser::parse_string(const char* text, outputStream* st) { + DirectivesParser cd(text, st); + if (cd.valid()) { + return cd.install_directives(); + } + st->flush(); + st->print_cr("Parsing of compiler directives failed"); + return false; +} + +bool DirectivesParser::has_file() { + return CompilerDirectivesFile != NULL; +} + +bool DirectivesParser::parse_from_flag() { + return parse_from_file(CompilerDirectivesFile, tty); +} + +bool DirectivesParser::parse_from_file(const char* filename, outputStream* st) { + assert(filename != NULL, "Test before calling this"); + if (!parse_from_file_inner(filename, st)) { + st->print_cr("Could not load file: %s", filename); + return false; + } + return true; +} + +bool DirectivesParser::parse_from_file_inner(const char* filename, outputStream* stream) { + struct stat st; + ResourceMark rm; + if (os::stat(filename, &st) == 0) { + // found file, open it + int file_handle = os::open(filename, 0, 0); + if (file_handle != -1) { + // read contents into resource array + char* buffer = NEW_RESOURCE_ARRAY(char, st.st_size+1); + size_t num_read = os::read(file_handle, (char*) buffer, st.st_size); + buffer[num_read] = '\0'; + // close file + os::close(file_handle); + return parse_string(buffer, stream); + } + } + return false; +} + +bool DirectivesParser::install_directives() { + // Pop from internal temporary stack and push to compileBroker. + CompilerDirectives* tmp = pop_tmp(); + int i = 0; + while (tmp != NULL) { + i++; + DirectivesStack::push(tmp); + tmp = pop_tmp(); + } + if (i == 0) { + _st->print_cr("No directives in file"); + return false; + } else { + _st->print_cr("%i compiler directives added", i); + if (PrintCompilerDirectives) { + // Print entire directives stack after new has been pushed. + DirectivesStack::print(_st); + } + return true; + } +} + +DirectivesParser::DirectivesParser(const char* text, outputStream* st) +: JSON(text, false, st), depth(0), current_directive(NULL), current_directiveset(NULL), _tmp_top(NULL) { +#ifndef PRODUCT + memset(stack, 0, MAX_DEPTH * sizeof(stack[0])); +#endif + parse(); +} + +DirectivesParser::~DirectivesParser() { +} + +const DirectivesParser::key DirectivesParser::keys[] = { + // name, keytype, allow_array, allowed_mask, set_function + { "c1", type_c1, 0, mask(type_directives), NULL, UnknownFlagType }, + { "c2", type_c2, 0, mask(type_directives), NULL, UnknownFlagType }, + { "match", type_match, 1, mask(type_directives), NULL, UnknownFlagType }, + { "inline", type_inline, 1, mask(type_directives) | mask(type_c1) | mask(type_c2), NULL, UnknownFlagType }, + { "enable", type_enable, 1, mask(type_directives) | mask(type_c1) | mask(type_c2), NULL, UnknownFlagType }, + { "preset", type_preset, 0, mask(type_c1) | mask(type_c2), NULL, UnknownFlagType }, + + // Global flags + #define common_flag_key(name, type, dvalue, compiler) \ + { #name, type_flag, 0, mask(type_directives) | mask(type_c1) | mask(type_c2), &DirectiveSet::set_##name, type##Flag}, + compilerdirectives_common_flags(common_flag_key) + compilerdirectives_c2_flags(common_flag_key) + compilerdirectives_c1_flags(common_flag_key) + #undef common_flag_key +}; + +const DirectivesParser::key DirectivesParser::dir_array_key = { + "top level directives array", type_dir_array, 0, 1 // Lowest bit means allow at top level +}; +const DirectivesParser::key DirectivesParser::dir_key = { + "top level directive", type_directives, 0, mask(type_dir_array) | 1 // Lowest bit means allow at top level +}; +const DirectivesParser::key DirectivesParser::value_array_key = { + "value array", type_value_array, 0, UINT_MAX // Allow all, checked by allow_array on other keys, not by allowed_mask from this key +}; + +const DirectivesParser::key* DirectivesParser::lookup_key(const char* str, size_t len) { + for (size_t i = 0; i < (sizeof(keys) / sizeof(keys[0])); i++) { + if (strncasecmp(keys[i].name, str, len) == 0) { + return &keys[i]; + } + } + return NULL; +} + +uint DirectivesParser::mask(keytype kt) { + return 1 << (kt + 1); +} + +bool DirectivesParser::push_key(const char* str, size_t len) { + bool result = true; + const key* k = lookup_key(str, len); + + if (k == NULL) { + // os::strdup + char* s = NEW_C_HEAP_ARRAY(char, len + 1, mtCompiler); + strncpy(s, str, len); + s[len] = '\0'; + error(KEY_ERROR, "No such key: '%s'.", s); + FREE_C_HEAP_ARRAY(char, s); + return false; + } + + return push_key(k); +} + +bool DirectivesParser::push_key(const key* k) { + assert(k->allowedmask != 0, "not allowed anywhere?"); + + // Exceeding the stack should not be possible with a valid compiler directive, + // and an invalid should abort before this happens + assert(depth < MAX_DEPTH, "exceeded stack depth"); + if (depth >= MAX_DEPTH) { + error(INTERNAL_ERROR, "Stack depth exceeded."); + return false; + } + + assert(stack[depth] == NULL, "element not nulled, something is wrong"); + + if (depth == 0 && !(k->allowedmask & 1)) { + error(KEY_ERROR, "Key '%s' not allowed at top level.", k->name); + return false; + } + + if (depth > 0) { + const key* prev = stack[depth - 1]; + if (!(k->allowedmask & mask(prev->type))) { + error(KEY_ERROR, "Key '%s' not allowed after '%s' key.", k->name, prev->name); + return false; + } + } + + stack[depth] = k; + depth++; + return true; +} + +const DirectivesParser::key* DirectivesParser::current_key() { + assert(depth > 0, "getting key from empty stack"); + if (depth == 0) { + return NULL; + } + return stack[depth - 1]; +} + +const DirectivesParser::key* DirectivesParser::pop_key() { + assert(depth > 0, "popping empty stack"); + if (depth == 0) { + error(INTERNAL_ERROR, "Popping empty stack."); + return NULL; + } + depth--; + + const key* k = stack[depth]; +#ifndef PRODUCT + stack[depth] = NULL; +#endif + + return k; +} + +bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* option_key, DirectiveSet* set) { + + void (DirectiveSet::*test)(void *args); + test = option_key->set; + + switch (t) { + case JSON_TRUE: + if (option_key->flag_type != boolFlag) { + error(VALUE_ERROR, "Cannot use bool value for an %s flag", flag_type_names[option_key->flag_type]); + return false; + } else { + bool val = true; + (set->*test)((void *)&val); + } + break; + + case JSON_FALSE: + if (option_key->flag_type != boolFlag) { + error(VALUE_ERROR, "Cannot use bool value for an %s flag", flag_type_names[option_key->flag_type]); + return false; + } else { + bool val = false; + (set->*test)((void *)&val); + } + break; + + case JSON_NUMBER_INT: + if (option_key->flag_type != intxFlag) { + if (option_key->flag_type == doubleFlag) { + double dval = (double)v->int_value; + (set->*test)((void *)&dval); + break; + } + error(VALUE_ERROR, "Cannot use int value for an %s flag", flag_type_names[option_key->flag_type]); + return false; + } else { + intx ival = v->int_value; + (set->*test)((void *)&ival); + } + break; + + case JSON_NUMBER_FLOAT: + if (option_key->flag_type != doubleFlag) { + error(VALUE_ERROR, "Cannot use double value for an %s flag", flag_type_names[option_key->flag_type]); + return false; + } else { + double dval = v->double_value; + (set->*test)((void *)&dval); + } + break; + + case JSON_STRING: + if (option_key->flag_type != ccstrFlag) { + error(VALUE_ERROR, "Cannot use string value for a %s flag", flag_type_names[option_key->flag_type]); + return false; + } else { + char* s = NEW_C_HEAP_ARRAY(char, v->str.length+1, mtCompiler); + strncpy(s, v->str.start, v->str.length + 1); + s[v->str.length] = '\0'; + (set->*test)((void *)&s); + } + break; + + default: + assert(0, "Should not reach here."); + } + return true; +} + +bool DirectivesParser::set_option(JSON_TYPE t, JSON_VAL* v) { + + const key* option_key = pop_key(); + const key* enclosing_key = current_key(); + + if (option_key->type == value_array_key.type) { + // Multi value array, we are really setting the value + // for the key one step further up. + option_key = pop_key(); + enclosing_key = current_key(); + + // Repush option_key and multi value marker, since + // we need to keep them until all multi values are set. + push_key(option_key); + push_key(&value_array_key); + } + + switch (option_key->type) { + case type_flag: + { + if (current_directiveset == NULL) { + assert(depth == 2, "Must not have active directive set"); + + if (!set_option_flag(t, v, option_key, current_directive->_c1_store)) { + return false; + } + if(!set_option_flag(t, v, option_key, current_directive->_c2_store)) { + return false; + } + } else { + assert(depth > 2, "Must have active current directive set"); + if (!set_option_flag(t, v, option_key, current_directiveset)) { + return false; + } + } + break; + } + + case type_match: + if (t != JSON_STRING) { + error(VALUE_ERROR, "Key of type %s needs a value of type string", option_key->name); + return false; + } + if (enclosing_key->type != type_directives) { + error(SYNTAX_ERROR, "Match keyword can only exist inside a directive"); + return false; + } + { + char* s = NEW_C_HEAP_ARRAY(char, v->str.length + 1, mtCompiler); + strncpy(s, v->str.start, v->str.length); + s[v->str.length] = '\0'; + + const char* error_msg = NULL; + if (!current_directive->add_match(s, error_msg)) { + assert (error_msg != NULL, "Must have valid error message"); + error(VALUE_ERROR, "Method pattern error: %s", error_msg); + } + FREE_C_HEAP_ARRAY(char, s); + } + break; + + case type_inline: + if (t != JSON_STRING) { + error(VALUE_ERROR, "Key of type %s needs a value of type string", option_key->name); + return false; + } + { + //char* s = strndup(v->str.start, v->str.length); + char* s = NEW_C_HEAP_ARRAY(char, v->str.length + 1, mtCompiler); + strncpy(s, v->str.start, v->str.length); + s[v->str.length] = '\0'; + + 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)) { + assert (error_msg != NULL, "Must have valid error message"); + error(VALUE_ERROR, "Method pattern error: %s", error_msg); + } + } else { + if (!current_directiveset->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); + } + } + FREE_C_HEAP_ARRAY(char, s); + } + break; + + case type_c1: + current_directiveset = current_directive->_c1_store; + if (t != JSON_TRUE && t != JSON_FALSE) { + error(VALUE_ERROR, "Key of type %s needs a true or false value", option_key->name); + return false; + } + break; + + case type_c2: + current_directiveset = current_directive->_c2_store; + if (t != JSON_TRUE && t != JSON_FALSE) { + error(VALUE_ERROR, "Key of type %s needs a true or false value", option_key->name); + return false; + } + break; + + case type_enable: + switch (enclosing_key->type) { + case type_c1: + case type_c2: + { + if (t != JSON_TRUE && t != JSON_FALSE) { + error(VALUE_ERROR, "Key of type %s enclosed in a %s key needs a true or false value", option_key->name, enclosing_key->name); + return false; + } + int val = (t == JSON_TRUE); + current_directiveset->set_Enable(&val); + break; + } + + case type_directives: + error(VALUE_ERROR, "Enable keyword not available for generic directive"); + return false; + + default: + error(INTERNAL_ERROR, "Unexpected enclosing type for key %s: %s", option_key->name, enclosing_key->name); + ShouldNotReachHere(); + return false; + } + break; + + default: + break; + } + + return true; +} + +bool DirectivesParser::callback(JSON_TYPE t, JSON_VAL* v, uint rlimit) { + const key* k; + + if (depth == 0) { + switch (t) { + case JSON_ARRAY_BEGIN: + return push_key(&dir_array_key); + + case JSON_OBJECT_BEGIN: + // push synthetic dir_array + push_key(&dir_array_key); + assert(depth == 1, "Make sure the stack are aligned with the directives"); + break; + + default: + error(SYNTAX_ERROR, "DirectivesParser can only start with an array containing directive objects, or one single directive."); + return false; + } + } + if (depth == 1) { + switch (t) { + case JSON_OBJECT_BEGIN: + // Parsing a new directive. + current_directive = new CompilerDirectives(); + return push_key(&dir_key); + + case JSON_ARRAY_END: + k = pop_key(); + + if (k->type != type_dir_array) { + error(SYNTAX_ERROR, "Expected end of directives array"); + return false; + } + return true; + + default: + error(SYNTAX_ERROR, "DirectivesParser can only start with an array containing directive objects, or one single directive."); + return false; + } + } else { + switch (t) { + case JSON_OBJECT_BEGIN: + k = current_key(); + switch (k->type) { + case type_c1: + current_directiveset = current_directive->_c1_store; + return true; + case type_c2: + current_directiveset = current_directive->_c2_store; + return true; + + case type_dir_array: + return push_key(&dir_key); + + default: + error(SYNTAX_ERROR, "The key '%s' does not allow an object to follow.", k->name); + return false; + } + return false; + + case JSON_OBJECT_END: + k = pop_key(); + switch (k->type) { + case type_c1: + case type_c2: + // This is how we now if options apply to a single or both directive sets + current_directiveset = NULL; + break; + + case type_directives: + // Check, finish and push to stack! + if (current_directive->match() == NULL) { + error(INTERNAL_ERROR, "Directive missing required match."); + return false; + } + current_directive->finalize(); + push_tmp(current_directive); + current_directive = NULL; + break; + + default: + error(INTERNAL_ERROR, "Object end with wrong key type on stack: %s.", k->name); + ShouldNotReachHere(); + return false; + } + return true; + + case JSON_ARRAY_BEGIN: + k = current_key(); + if (!(k->allow_array_value)) { + if (k->type == type_dir_array) { + error(SYNTAX_ERROR, "Array not allowed inside top level array, expected directive object."); + } else { + error(VALUE_ERROR, "The key '%s' does not allow an array of values.", k->name); + } + return false; + } + return push_key(&value_array_key); + + case JSON_ARRAY_END: + k = pop_key(); // Pop multi value marker + assert(k->type == value_array_key.type, "array end for level != 0 should terminate multi value"); + k = pop_key(); // Pop key for option that was set + return true; + + case JSON_KEY: + return push_key(v->str.start, v->str.length); + + case JSON_STRING: + case JSON_NUMBER_INT: + case JSON_NUMBER_FLOAT: + case JSON_TRUE: + case JSON_FALSE: + case JSON_NULL: + return set_option(t, v); + + default: + error(INTERNAL_ERROR, "Unknown JSON type: %d.", t); + ShouldNotReachHere(); + return false; + } + } +} + +#ifndef PRODUCT +void DirectivesParser::test(const char* text, bool should_pass) { + DirectivesParser cd(text, tty); + if (should_pass) { + assert(cd.valid() == true, "failed on a valid DirectivesParser string"); + if (VerboseInternalVMTests) { + tty->print("-- DirectivesParser test passed as expected --\n"); + } + } else { + assert(cd.valid() == false, "succeeded on an invalid DirectivesParser string"); + if (VerboseInternalVMTests) { + tty->print("-- DirectivesParser test failed as expected --\n"); + } + } +} + +bool DirectivesParser::test() { + DirectivesParser::test("{}", false); + DirectivesParser::test("[]", true); + DirectivesParser::test("[{}]", false); + DirectivesParser::test("[{},{}]", false); + DirectivesParser::test("{},{}", false); + + DirectivesParser::test( + "[" "\n" + " {" "\n" + " match: \"foo/bar.*\"," "\n" + " inline : \"+java/util.*\"," "\n" + " PrintAssembly: true," "\n" + " BreakAtExecute: true," "\n" + " }" "\n" + "]" "\n", true); + + DirectivesParser::test( + "[" "\n" + " [" "\n" + " {" "\n" + " match: \"foo/bar.*\"," "\n" + " inline : \"+java/util.*\"," "\n" + " PrintAssembly: true," "\n" + " BreakAtExecute: true," "\n" + " }" "\n" + " ]" "\n" + "]" "\n", false); + + /*DirectivesParser::test( + "[" "\n" + " {" "\n" + " match: \"foo/bar.*\"," "\n" + " c1: {" + " PrintIntrinsics: false," "\n" + " }" "\n" + " }" "\n" + "]" "\n", false);*/ + + DirectivesParser::test( + "[" "\n" + " {" "\n" + " match: \"foo/bar.*\"," "\n" + " c2: {" "\n" + " PrintInlining: false," "\n" + " }" "\n" + " }" "\n" + "]" "\n", true); + + DirectivesParser::test( + "[" "\n" + " {" "\n" + " match: \"foo/bar.*\"," "\n" + " PrintInlining: [" "\n" + " true," "\n" + " false" "\n" + " ]," "\n" + " }" "\n" + "]" "\n", false); + + DirectivesParser::test( + "[" "\n" + " {" + " // pattern to match against class+method+signature" "\n" + " // leading and trailing wildcard (*) allowed" "\n" + " match: \"foo/bar.*\"," "\n" + "" "\n" + " // override defaults for specified compiler" "\n" + " // we may differentiate between levels too. TBD." "\n" + " c1: {" "\n" + " //override c1 presets " "\n" + " DumpReplay: false," "\n" + " BreakAtCompile: true," "\n" + " }," "\n" + "" "\n" + " c2: {" "\n" + " // control inlining of method" "\n" + " // + force inline, - dont inline" "\n" + " inline : \"+java/util.*\"," "\n" + " PrintInlining: true," "\n" + " }," "\n" + "" "\n" + " // directives outside a specific preset applies to all compilers" "\n" + " inline : [ \"+java/util.*\", \"-com/sun.*\"]," "\n" + " BreakAtExecute: true," "\n" + " Log: true," "\n" + " }," "\n" + " {" "\n" + " // matching several patterns require an array" "\n" + " match: [\"baz.*\",\"frob.*\"]," "\n" + "" "\n" + " // applies to all compilers" "\n" + " // + force inline, - dont inline" "\n" + " inline : [ \"+java/util.*\", \"-com/sun.*\" ]," "\n" + " PrintInlining: true," "\n" + "" "\n" + " // force matching compiles to be blocking/syncronous" "\n" + " PrintNMethods: true" "\n" + " }," "\n" + "]" "\n", true); + + // Test max stack depth + DirectivesParser::test( + "[" "\n" // depth 1: type_dir_array + " {" "\n" // depth 2: type_directives + " match: \"*.*\"," // match required + " c1:" "\n" // depth 3: type_c1 + " {" "\n" + " inline:" "\n" // depth 4: type_inline + " [" "\n" // depth 5: type_value_array + " \"foo\"," "\n" + " \"bar\"," "\n" + " ]" "\n" // depth 3: pop type_value_array and type_inline keys + " }" "\n" // depth 2: pop type_c1 key + " }" "\n" // depth 1: pop type_directives key + "]" "\n", true); // depth 0: pop type_dir_array key + + // Test max stack depth + DirectivesParser::test( + "[{c1:{c1:{c1:{c1:{c1:{c1:{c1:{}}}}}}}}]", false); + + DirectivesParser::test( + "[" "\n" + " {" "\n" + " c1: true," "\n" + " c2: true," "\n" + " match: true," "\n" + " inline: true," "\n" + " enable: true," "\n" + " c1: {" "\n" + " preset: true," "\n" + " }" "\n" + " }" "\n" + "]" "\n", false); + + return true; +} + +#endif diff --git a/hotspot/src/share/vm/compiler/directivesParser.hpp b/hotspot/src/share/vm/compiler/directivesParser.hpp new file mode 100644 index 00000000000..fd5fe3be20c --- /dev/null +++ b/hotspot/src/share/vm/compiler/directivesParser.hpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_COMPILER_DIRECTIVESPARSER_HPP +#define SHARE_VM_COMPILER_DIRECTIVESPARSER_HPP + +#include "utilities/json.hpp" +#include "compiler/compilerDirectives.hpp" + +enum FlagType { + boolFlag, + intxFlag, + doubleFlag, + ccstrFlag, + UnknownFlagType +}; + +static const char* flag_type_names[] = { + "bool", + "int", + "double", + "string", + "unknown" +}; + +class DirectivesParser : public JSON { +public: + static bool has_file(); + static bool parse_from_flag(); + static bool parse_from_file(const char* filename, outputStream* st); + static bool parse_string(const char* string, outputStream* st); + bool install_directives(); + +private: + DirectivesParser(const char* text, outputStream* st); + ~DirectivesParser(); + + bool callback(JSON_TYPE t, JSON_VAL* v, uint level); + static bool parse_from_file_inner(const char* filename, outputStream* st); + + // types of "keys". i.e recognized : pairs in our JSON syntax + typedef enum { + type_c1, + type_c2, + type_enable, + type_preset, + type_match, + type_inline, + + // After here, there is no correlation between + // keytype and keys array + //type_strategy, + type_flag, + //type_dir, + + // Synthetic. + type_dir_array, + type_directives, + type_value_array + } keytype; + + // name, type, dtd info and maybe a setter + // this is how we map key-values + typedef struct { + const char *name; + keytype type; + uint allow_array_value : 1; + uint allowedmask; + void (DirectiveSet::*set)(void* arg); + FlagType flag_type; + } key; + + // Array with valid keys for the directive file + static const key keys[]; + // Marker for outermost moosewings/array + static const key dir_array_key; + // Marker for a directives set (these are "implicit" objects, as in not named) + static const key dir_key; + // Marker for a multi value + static const key value_array_key; + + // A compiler directive shouldn't be able to use more than 5 stack slots. + // Example of max stack usage: + // depth 1: type_dir_array [ + // depth 2: type_directives { + // depth 3: type_c1 c1: { + // depth 4: type_inline inline: + // depth 5: type_value_array [ ... + static const uint MAX_DEPTH = 5; + const key* stack[MAX_DEPTH]; + uint depth; + + bool push_key(const char* str, size_t len); + bool push_key(const key* k); + const key* current_key(); + const key* pop_key(); + static const key* lookup_key(const char* s, size_t len); + + bool set_option(JSON_TYPE t, JSON_VAL* v); + bool set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* option_key, DirectiveSet* set); + + CompilerDirectives* current_directive; + DirectiveSet* current_directiveset; + + void push_tmp(CompilerDirectives* dir); + CompilerDirectives* pop_tmp(); + CompilerDirectives* _tmp_top; // temporary storage for dirs while parsing + + static uint mask(keytype kt); + +#ifndef PRODUCT + static void test(const char* json, bool valid); +public: + static bool test(); +#endif +}; + +#endif // SHARE_VM_COMPILER_DIRECTIVESPARSER_HPP diff --git a/hotspot/src/share/vm/compiler/methodMatcher.cpp b/hotspot/src/share/vm/compiler/methodMatcher.cpp index d48c8944bd9..16f7855756e 100644 --- a/hotspot/src/share/vm/compiler/methodMatcher.cpp +++ b/hotspot/src/share/vm/compiler/methodMatcher.cpp @@ -342,6 +342,107 @@ void MethodMatcher::print_base(outputStream* st) { } } +BasicMatcher* BasicMatcher::parse_method_pattern(char* line, const char*& error_msg) { + assert(error_msg == NULL, "Don't call here with error_msg already set"); + BasicMatcher* bm = new BasicMatcher(); + MethodMatcher::parse_method_pattern(line, error_msg, bm); + if (error_msg != NULL) { + delete bm; + return NULL; + } + // check for bad trailing characters + int bytes_read = 0; + sscanf(line, "%*[ \t]%n", &bytes_read); + if (line[bytes_read] != '\0') { + error_msg = "Unrecognized trailing text after method pattern"; + delete bm; + return NULL; + } + return bm; +} +bool BasicMatcher::match(methodHandle method) { + for (BasicMatcher* current = this; current != NULL; current = current->next()) { + if (current->matches(method)) { + return true; + } + } + return false; +} +void InlineMatcher::print(outputStream* st) { + if (_inline_action == InlineMatcher::force_inline) { + st->print("+"); + } else { + st->print("-"); + } + print_base(st); +} + +InlineMatcher* InlineMatcher::parse_method_pattern(char* line, const char*& error_msg) { + assert(error_msg == NULL, "Dont call here with error_msg already set"); + InlineMatcher* im = new InlineMatcher(); + MethodMatcher::parse_method_pattern(line, error_msg, im); + if (error_msg != NULL) { + delete im; + return NULL; + } + return im; +} + +bool InlineMatcher::match(methodHandle method, int inline_action) { + for (InlineMatcher* current = this; current != NULL; current = current->next()) { + if (current->matches(method)) { + return (current->_inline_action == inline_action); + } + } + return false; +} + +InlineMatcher* InlineMatcher::parse_inline_pattern(char* str, const char*& error_msg) { + // check first token is +/- + InlineType _inline_action; + switch (str[0]) { + case '-': + _inline_action = InlineMatcher::dont_inline; + break; + case '+': + _inline_action = InlineMatcher::force_inline; + break; + default: + error_msg = "Missing leading inline type (+/-)"; + return NULL; + } + str++; + + int bytes_read = 0; + assert(error_msg== NULL, "error_msg must not be set yet"); + InlineMatcher* im = InlineMatcher::parse_method_pattern(str, error_msg); + if (im == NULL) { + assert(error_msg != NULL, "Must have error message"); + return NULL; + } + im->set_action(_inline_action); + return im; +} + +InlineMatcher* InlineMatcher::clone() { + InlineMatcher* m = new InlineMatcher(); + m->_class_mode = _class_mode; + m->_method_mode = _method_mode; + m->_inline_action = _inline_action; + m->_class_name = _class_name; + if(_class_name != NULL) { + _class_name->increment_refcount(); + } + m->_method_name = _method_name; + if (_method_name != NULL) { + _method_name->increment_refcount(); + } + m->_signature = _signature; + if (_signature != NULL) { + _signature->increment_refcount(); + } + return m; +} diff --git a/hotspot/src/share/vm/compiler/methodMatcher.hpp b/hotspot/src/share/vm/compiler/methodMatcher.hpp index aba72726224..938a14b0a55 100644 --- a/hotspot/src/share/vm/compiler/methodMatcher.hpp +++ b/hotspot/src/share/vm/compiler/methodMatcher.hpp @@ -81,35 +81,8 @@ public: _next(next) { } - static BasicMatcher* parse_method_pattern(char* line, const char*& error_msg) { - assert(error_msg == NULL, "Dont call here with error_msg already set"); - BasicMatcher* bm = new BasicMatcher(); - MethodMatcher::parse_method_pattern(line, error_msg, bm); - if (error_msg != NULL) { - delete bm; - return NULL; - } - - // check for bad trailing characters - int bytes_read = 0; - sscanf(line, "%*[ \t]%n", &bytes_read); - if (line[bytes_read] != '\0') { - error_msg = "Unrecognized trailing text after method pattern"; - delete bm; - return NULL; - } - return bm; - } - - bool match(methodHandle method) { - for (BasicMatcher* current = this; current != NULL; current = current->next()) { - if (current->matches(method)) { - return true; - } - } - return false; - } - + static BasicMatcher* parse_method_pattern(char* line, const char*& error_msg); + bool match(methodHandle method); void set_next(BasicMatcher* next) { _next = next; } BasicMatcher* next() { return _next; } @@ -122,5 +95,33 @@ public: } }; +class InlineMatcher : public MethodMatcher { +public: + enum InlineType { + unknown_inline, + dont_inline, + force_inline + }; + +private: + InlineType _inline_action; + InlineMatcher * _next; + + InlineMatcher() : MethodMatcher(), + _inline_action(unknown_inline), _next(NULL) { + } + +public: + static InlineMatcher* parse_method_pattern(char* line, const char*& error_msg); + bool match(methodHandle method, int inline_action); + void print(outputStream* st); + void set_next(InlineMatcher* next) { _next = next; } + InlineMatcher* next() { return _next; } + void set_action(InlineType inline_action) { _inline_action = inline_action; } + int inline_action() { return _inline_action; } + static InlineMatcher* parse_inline_pattern(char* line, const char*& error_msg); + InlineMatcher* clone(); +}; + #endif // SHARE_VM_COMPILER_METHODMATCHER_HPP diff --git a/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp b/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp index ca747e6bc7c..7cb959a96b8 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp @@ -145,7 +145,7 @@ void JVMCICompiler::compile_method(methodHandle method, int entry_bci, JVMCIEnv* // Compilation entry point for methods -void JVMCICompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) { +void JVMCICompiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive) { ShouldNotReachHere(); } diff --git a/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp b/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp index bf11cc528d4..b4d3a4964bf 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp +++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp @@ -69,7 +69,7 @@ public: void bootstrap(); // Compilation entry point for methods - virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci); + virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive); void compile_method(methodHandle target, int entry_bci, JVMCIEnv* env); diff --git a/hotspot/src/share/vm/opto/block.cpp b/hotspot/src/share/vm/opto/block.cpp index 3be4e7e6ac0..e33af9f4f31 100644 --- a/hotspot/src/share/vm/opto/block.cpp +++ b/hotspot/src/share/vm/opto/block.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "libadt/vectset.hpp" #include "memory/allocation.inline.hpp" +#include "compiler/compilerDirectives.hpp" #include "opto/block.hpp" #include "opto/cfgnode.hpp" #include "opto/chaitin.hpp" @@ -365,7 +366,7 @@ PhaseCFG::PhaseCFG(Arena* arena, RootNode* root, Matcher& matcher) , _node_to_block_mapping(arena) , _node_latency(NULL) #ifndef PRODUCT -, _trace_opto_pipelining(TraceOptoPipelining || C->method_has_option("TraceOptoPipelining")) +, _trace_opto_pipelining(C->directive()->TraceOptoPipeliningOption) #endif #ifdef ASSERT , _raw_oops(arena) diff --git a/hotspot/src/share/vm/opto/block.hpp b/hotspot/src/share/vm/opto/block.hpp index 501495e0513..ad30a167130 100644 --- a/hotspot/src/share/vm/opto/block.hpp +++ b/hotspot/src/share/vm/opto/block.hpp @@ -368,7 +368,6 @@ public: class PhaseCFG : public Phase { friend class VMStructs; private: - // Root of whole program RootNode* _root; diff --git a/hotspot/src/share/vm/opto/bytecodeInfo.cpp b/hotspot/src/share/vm/opto/bytecodeInfo.cpp index 3d4a54f173e..9882317cf0b 100644 --- a/hotspot/src/share/vm/opto/bytecodeInfo.cpp +++ b/hotspot/src/share/vm/opto/bytecodeInfo.cpp @@ -108,7 +108,7 @@ bool InlineTree::should_inline(ciMethod* callee_method, ciMethod* caller_method, int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) { // Allows targeted inlining - if (callee_method->should_inline()) { + if (C->directive()->should_inline(callee_method)) { *wci_result = *(WarmCallInfo::always_hot()); if (C->print_inlining() && Verbose) { CompileTask::print_inline_indent(inline_level()); @@ -222,12 +222,12 @@ bool InlineTree::should_not_inline(ciMethod *callee_method, } // ignore heuristic controls on inlining - if (callee_method->should_inline()) { + if (C->directive()->should_inline(callee_method)) { set_msg("force inline by CompileCommand"); return false; } - if (callee_method->should_not_inline()) { + if (C->directive()->should_not_inline(callee_method)) { set_msg("disallowed by CompileCommand"); return true; } diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index 1782abfd0a1..ae90ae538f6 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -154,7 +154,7 @@ notproduct(bool, PrintOptoStatistics, false, \ "Print New compiler statistics") \ \ - notproduct(bool, PrintOptoAssembly, false, \ + diagnostic(bool, PrintOptoAssembly, false, \ "Print New compiler assembly output") \ \ develop_pd(bool, OptoPeephole, \ @@ -632,7 +632,7 @@ develop(bool, PrintDominators, false, \ "Print out dominator trees for GVN") \ \ - notproduct(bool, TraceSpilling, false, \ + diagnostic(bool, TraceSpilling, false, \ "Trace spilling") \ \ diagnostic(bool, TraceTypeProfile, false, \ diff --git a/hotspot/src/share/vm/opto/c2compiler.cpp b/hotspot/src/share/vm/opto/c2compiler.cpp index aaed3d6b939..9dfcd5c79e3 100644 --- a/hotspot/src/share/vm/opto/c2compiler.cpp +++ b/hotspot/src/share/vm/opto/c2compiler.cpp @@ -94,15 +94,16 @@ void C2Compiler::initialize() { } } -void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) { +void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* directive) { assert(is_initialized(), "Compiler thread must be initialized"); bool subsume_loads = SubsumeLoads; bool do_escape_analysis = DoEscapeAnalysis && !env->should_retain_local_variables(); bool eliminate_boxing = EliminateAutoBox; + while (!env->failing()) { // Attempt to compile while subsuming loads into machine instructions. - Compile C(env, this, target, entry_bci, subsume_loads, do_escape_analysis, eliminate_boxing); + Compile C(env, this, target, entry_bci, subsume_loads, do_escape_analysis, eliminate_boxing, directive); // Check result and retry if appropriate. if (C.failure_reason() != NULL) { diff --git a/hotspot/src/share/vm/opto/c2compiler.hpp b/hotspot/src/share/vm/opto/c2compiler.hpp index f8308190444..016b4908e33 100644 --- a/hotspot/src/share/vm/opto/c2compiler.hpp +++ b/hotspot/src/share/vm/opto/c2compiler.hpp @@ -41,7 +41,8 @@ public: // Compilation entry point for methods void compile_method(ciEnv* env, ciMethod* target, - int entry_bci); + int entry_bci, + DirectiveSet* directive); // sentinel value used to trigger backtracking in compile_method(). static const char* retry_no_subsuming_loads(); diff --git a/hotspot/src/share/vm/opto/chaitin.cpp b/hotspot/src/share/vm/opto/chaitin.cpp index fd03d4146c5..3a9e0c03a6e 100644 --- a/hotspot/src/share/vm/opto/chaitin.cpp +++ b/hotspot/src/share/vm/opto/chaitin.cpp @@ -211,7 +211,7 @@ PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher, bool sc , _scratch_int_pressure(0, INTPRESSURE) , _scratch_float_pressure(0, FLOATPRESSURE) #ifndef PRODUCT - , _trace_spilling(TraceSpilling || C->method_has_option("TraceSpilling")) + , _trace_spilling(C->directive()->TraceSpillingOption) #endif { Compile::TracePhase tp("ctorChaitin", &timers[_t_ctorChaitin]); diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index ae26d11658f..0bc6b09b45c 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -464,7 +464,7 @@ CompileWrapper::CompileWrapper(Compile* compile) : _compile(compile) { Type::Initialize(compile); _compile->set_scratch_buffer_blob(NULL); _compile->begin_method(); - _compile->clone_map().set_debug(_compile->has_method() && _compile->method_has_option(_compile->clone_map().debug_option_name)); + _compile->clone_map().set_debug(_compile->has_method() && _compile->directive()->CloneMapDebugOption); } CompileWrapper::~CompileWrapper() { _compile->end_method(); @@ -496,7 +496,7 @@ void Compile::print_compile_messages() { tty->print_cr("** Bailout: Recompile without boxing elimination **"); tty->print_cr("*********************************************************"); } - if (env()->break_at_compile()) { + if (C->directive()->BreakAtCompileOption) { // Open the debugger when compiling this method. tty->print("### Breaking when compiling: "); method()->print_short_name(); @@ -617,9 +617,10 @@ debug_only( int Compile::_debug_idx = 100000; ) Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr_bci, - bool subsume_loads, bool do_escape_analysis, bool eliminate_boxing ) + bool subsume_loads, bool do_escape_analysis, bool eliminate_boxing, DirectiveSet* directive) : Phase(Compiler), _env(ci_env), + _directive(directive), _log(ci_env->log()), _compile_id(ci_env->compile_id()), _save_argument_registers(false), @@ -649,7 +650,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr _dead_node_list(comp_arena()), _dead_node_count(0), #ifndef PRODUCT - _trace_opto_output(TraceOptoOutput || method()->has_option("TraceOptoOutput")), + _trace_opto_output(directive->TraceOptoOutputOption), _in_dump_cnt(0), _printer(IdealGraphPrinter::printer()), #endif @@ -673,7 +674,11 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr _interpreter_frame_size(0), _max_node_limit(MaxNodeLimit) { C = this; - +#ifndef PRODUCT + if (_printer != NULL) { + _printer->set_compile(this); + } +#endif CompileWrapper cw(this); if (CITimeVerbose) { @@ -687,9 +692,9 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr TraceTime t2(NULL, &_t_methodCompilation, CITime, false); #ifndef PRODUCT - bool print_opto_assembly = PrintOptoAssembly || _method->has_option("PrintOptoAssembly"); + bool print_opto_assembly = directive->PrintOptoAssemblyOption; if (!print_opto_assembly) { - bool print_assembly = (PrintAssembly || _method->should_print_assembly()); + bool print_assembly = directive->PrintAssemblyOption; if (print_assembly && !Disassembler::can_decode()) { tty->print_cr("PrintAssembly request changed to PrintOptoAssembly"); print_opto_assembly = true; @@ -698,12 +703,12 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr set_print_assembly(print_opto_assembly); set_parsed_irreducible_loop(false); - if (method()->has_option("ReplayInline")) { + if (directive->ReplayInlineOption) { _replay_inline_data = ciReplay::load_inline_data(method(), entry_bci(), ci_env->comp_level()); } #endif - set_print_inlining(PrintInlining || method()->has_option("PrintInlining") NOT_PRODUCT( || PrintOptoInlining)); - set_print_intrinsics(PrintIntrinsics || method()->has_option("PrintIntrinsics")); + set_print_inlining(directive->PrintInliningOption NOT_PRODUCT( || PrintOptoInlining)); + set_print_intrinsics(directive->PrintIntrinsicsOption); set_has_irreducible_loop(true); // conservative until build_loop_tree() reset it if (ProfileTraps RTM_OPT_ONLY( || UseRTMLocking )) { @@ -837,8 +842,8 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr // Drain the list. Finish_Warm(); #ifndef PRODUCT - if (_printer && _printer->should_print(_method)) { - _printer->print_inlining(this); + if (_printer && _printer->should_print(1)) { + _printer->print_inlining(); } #endif @@ -871,10 +876,10 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr NOT_PRODUCT( verify_barriers(); ) // Dump compilation data to replay it. - if (method()->has_option("DumpReplay")) { + if (directive->DumpReplayOption) { env()->dump_replay_data(_compile_id); } - if (method()->has_option("DumpInline") && (ilt() != NULL)) { + if (directive->DumpInlineOption && (ilt() != NULL)) { env()->dump_inline_data(_compile_id); } @@ -918,9 +923,9 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr frame_size_in_words(), _oop_map_set, &_handler_table, &_inc_table, compiler, - env()->comp_level(), has_unsafe_access(), SharedRuntime::is_wide_vector(max_vector_size()), + _directive, rtm_state() ); @@ -938,9 +943,11 @@ Compile::Compile( ciEnv* ci_env, int is_fancy_jump, bool pass_tls, bool save_arg_registers, - bool return_pc ) + bool return_pc, + DirectiveSet* directive) : Phase(Compiler), _env(ci_env), + _directive(directive), _log(ci_env->log()), _compile_id(0), _save_argument_registers(save_arg_registers), @@ -1090,7 +1097,7 @@ void Compile::Init(int aliaslevel) { Copy::zero_to_bytes(_trap_hist, sizeof(_trap_hist)); set_decompile_count(0); - set_do_freq_based_layout(BlockLayoutByFrequency || method_has_option("BlockLayoutByFrequency")); + set_do_freq_based_layout(_directive->BlockLayoutByFrequencyOption); set_num_loop_opts(LoopOptsCount); set_do_inlining(Inline); set_max_inline_size(MaxInlineSize); @@ -1103,7 +1110,7 @@ void Compile::Init(int aliaslevel) { bool do_vector = false; if (AllowVectorizeOnDemand) { - if (has_method() && (method()->has_option("Vectorize") || method()->has_option("VectorizeDebug"))) { + if (has_method() && (_directive->VectorizeOption || _directive->VectorizeDebugOption)) { set_do_vector_loop(true); } else if (has_method() && method()->name() != 0 && method()->intrinsic_id() == vmIntrinsics::_forEachRemaining) { @@ -1118,7 +1125,8 @@ void Compile::Init(int aliaslevel) { set_age_code(has_method() && method()->profile_aging()); set_rtm_state(NoRTM); // No RTM lock eliding by default - method_has_option_value("MaxNodeLimit", _max_node_limit); + _max_node_limit = _directive->MaxNodeLimitOption; + #if INCLUDE_RTM_OPT if (UseRTMLocking && has_method() && (method()->method_data_or_null() != NULL)) { int rtm_state = method()->method_data()->rtm_state(); @@ -2091,7 +2099,7 @@ void Compile::Optimize() { TracePhase tp("optimizer", &timers[_t_optimizer]); #ifndef PRODUCT - if (env()->break_at_compile()) { + if (_directive->BreakAtCompileOption) { BREAKPOINT; } @@ -4357,7 +4365,6 @@ bool Compile::randomized_select(int count) { return (os::random() & RANDOMIZED_DOMAIN_MASK) < (RANDOMIZED_DOMAIN / count); } -const char* CloneMap::debug_option_name = "CloneMapDebug"; CloneMap& Compile::clone_map() { return _clone_map; } void Compile::set_clone_map(Dict* d) { _clone_map._dict = d; } diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp index eb09b285789..4a77097777b 100644 --- a/hotspot/src/share/vm/opto/compile.hpp +++ b/hotspot/src/share/vm/opto/compile.hpp @@ -391,6 +391,7 @@ class Compile : public Phase { // Compilation environment. Arena _comp_arena; // Arena with lifetime equivalent to Compile ciEnv* _env; // CI interface + DirectiveSet* _directive; // Compiler directive CompileLog* _log; // from CompilerThread const char* _failure_reason; // for record_failure/failing pattern GrowableArray* _intrinsics; // List of intrinsics. @@ -527,6 +528,10 @@ class Compile : public Phase { print_inlining_stream()->print("%s", ss.as_string()); } +#ifndef PRODUCT + IdealGraphPrinter* printer() { return _printer; } +#endif + void log_late_inline(CallGenerator* cg); void log_inline_id(CallGenerator* cg); void log_inline_failure(const char* msg); @@ -578,6 +583,7 @@ class Compile : public Phase { // ID for this compilation. Useful for setting breakpoints in the debugger. int compile_id() const { return _compile_id; } + DirectiveSet* directive() const { return _directive; } // Does this compilation allow instructions to subsume loads? User // instructions that subsume a load may result in an unschedulable @@ -671,10 +677,7 @@ class Compile : public Phase { bool method_has_option(const char * option) { return method() != NULL && method()->has_option(option); } - template - bool method_has_option_value(const char * option, T& value) { - return method() != NULL && method()->has_option_value(option, value); - } + #ifndef PRODUCT bool trace_opto_output() const { return _trace_opto_output; } bool parsed_irreducible_loop() const { return _parsed_irreducible_loop; } @@ -692,8 +695,8 @@ class Compile : public Phase { void begin_method() { #ifndef PRODUCT - if (_printer && _printer->should_print(_method)) { - _printer->begin_method(this); + if (_printer && _printer->should_print(1)) { + _printer->begin_method(); } #endif C->_latest_stage_start_counter.stamp(); @@ -711,8 +714,8 @@ class Compile : public Phase { #ifndef PRODUCT - if (_printer && _printer->should_print(_method)) { - _printer->print_method(this, CompilerPhaseTypeHelper::to_string(cpt), level); + if (_printer && _printer->should_print(level)) { + _printer->print_method(CompilerPhaseTypeHelper::to_string(cpt), level); } #endif C->_latest_stage_start_counter.stamp(); @@ -728,7 +731,7 @@ class Compile : public Phase { event.commit(); } #ifndef PRODUCT - if (_printer && _printer->should_print(_method)) { + if (_printer && _printer->should_print(level)) { _printer->end_method(); } #endif @@ -1107,7 +1110,7 @@ class Compile : public Phase { // continuation. Compile(ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int entry_bci, bool subsume_loads, bool do_escape_analysis, - bool eliminate_boxing); + bool eliminate_boxing, DirectiveSet* directive); // Second major entry point. From the TypeFunc signature, generate code // to pass arguments from the Java calling convention to the C calling @@ -1115,7 +1118,7 @@ class Compile : public Phase { Compile(ciEnv* ci_env, const TypeFunc *(*gen)(), address stub_function, const char *stub_name, int is_fancy_jump, bool pass_tls, - bool save_arg_registers, bool return_pc); + bool save_arg_registers, bool return_pc, DirectiveSet* directive); // From the TypeFunc signature, generate code to pass arguments // from Compiled calling convention to Interpreter's calling convention diff --git a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp index 6c03eaa1e2c..730b3a85733 100644 --- a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp +++ b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp @@ -292,11 +292,11 @@ void IdealGraphPrinter::print_inline_tree(InlineTree *tree) { } -void IdealGraphPrinter::print_inlining(Compile* compile) { +void IdealGraphPrinter::print_inlining() { // Print inline tree if (_should_send_method) { - InlineTree *inlineTree = compile->ilt(); + InlineTree *inlineTree = C->ilt(); if (inlineTree != NULL) { print_inline_tree(inlineTree); } else { @@ -306,9 +306,9 @@ void IdealGraphPrinter::print_inlining(Compile* compile) { } // Has to be called whenever a method is compiled -void IdealGraphPrinter::begin_method(Compile* compile) { +void IdealGraphPrinter::begin_method() { - ciMethod *method = compile->method(); + ciMethod *method = C->method(); assert(_output, "output stream must exist!"); assert(method, "null methods are not allowed!"); assert(!_current_method, "current method must be null!"); @@ -662,16 +662,14 @@ void IdealGraphPrinter::walk_nodes(Node *start, bool edges, VectorSet* temp_set) } } -void IdealGraphPrinter::print_method(Compile* compile, const char *name, int level, bool clear_nodes) { - print(compile, name, (Node *)compile->root(), level, clear_nodes); +void IdealGraphPrinter::print_method(const char *name, int level, bool clear_nodes) { + print(name, (Node *)C->root(), level, clear_nodes); } // Print current ideal graph -void IdealGraphPrinter::print(Compile* compile, const char *name, Node *node, int level, bool clear_nodes) { +void IdealGraphPrinter::print(const char *name, Node *node, int level, bool clear_nodes) { - if (!_current_method || !_should_send_method || !should_print(_current_method, level)) return; - - this->C = compile; + if (!_current_method || !_should_send_method || !should_print(level)) return; // Warning, unsafe cast? _chaitin = (PhaseChaitin *)C->regalloc(); @@ -722,10 +720,8 @@ void IdealGraphPrinter::print(Compile* compile, const char *name, Node *node, in } // Should method be printed? -bool IdealGraphPrinter::should_print(ciMethod* method, int level) { - intx ideal_graph_level = PrintIdealGraphLevel; - method->has_option_value("PrintIdealGraphLevel", ideal_graph_level); // update value with per-method value (if available) - return ideal_graph_level >= level; +bool IdealGraphPrinter::should_print(int level) { + return C->directive()->IGVPrintLevelOption >= level; } extern const char *NodeClassNames[]; diff --git a/hotspot/src/share/vm/opto/idealGraphPrinter.hpp b/hotspot/src/share/vm/opto/idealGraphPrinter.hpp index 4ddb682e047..2f4b9faf0cd 100644 --- a/hotspot/src/share/vm/opto/idealGraphPrinter.hpp +++ b/hotspot/src/share/vm/opto/idealGraphPrinter.hpp @@ -127,13 +127,14 @@ class IdealGraphPrinter : public CHeapObj { bool traverse_outs(); void set_traverse_outs(bool b); - void print_inlining(Compile* compile); - void begin_method(Compile* compile); + void print_inlining(); + void begin_method(); void end_method(); - void print_method(Compile* compile, const char *name, int level=1, bool clear_nodes = false); - void print(Compile* compile, const char *name, Node *root, int level=1, bool clear_nodes = false); + void print_method(const char *name, int level=1, bool clear_nodes = false); + void print(const char *name, Node *root, int level=1, bool clear_nodes = false); void print_xml(const char *name); - static bool should_print(ciMethod* method, int level = 1); + bool should_print(int level); + void set_compile(Compile* compile) {C = compile; } }; #endif diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index e62b66e8d89..6f9dc658979 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -326,9 +326,10 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) { // methods access VM-internal data. VM_ENTRY_MARK; methodHandle mh(THREAD, m->get_Method()); - methodHandle ct(THREAD, method()->get_Method()); is_available = compiler->is_intrinsic_supported(mh, is_virtual) && - !vmIntrinsics::is_disabled_by_flags(mh, ct); + !C->directive()->is_intrinsic_disabled(mh) && + !vmIntrinsics::is_disabled_by_flags(mh); + } if (is_available) { diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp index fc8cfdc8ca6..7b0c074f686 100644 --- a/hotspot/src/share/vm/opto/output.cpp +++ b/hotspot/src/share/vm/opto/output.cpp @@ -28,6 +28,7 @@ #include "code/debugInfo.hpp" #include "code/debugInfoRec.hpp" #include "compiler/compileBroker.hpp" +#include "compiler/compilerDirectives.hpp" #include "compiler/oopMap.hpp" #include "memory/allocation.inline.hpp" #include "opto/ad.hpp" @@ -89,9 +90,8 @@ void Compile::Output() { } - // Break before main entry point - if( (_method && _method->break_at_execute()) + if( (_method && C->directive()->BreakAtExecuteOption) #ifndef PRODUCT ||(OptoBreakpoint && is_method_compilation()) ||(OptoBreakpointOSR && is_osr_compilation()) diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index 5be7b039b9d..cd68d761568 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -2378,13 +2378,13 @@ void Parse::do_one_bytecode() { } #ifndef PRODUCT - IdealGraphPrinter *printer = IdealGraphPrinter::printer(); - if (printer && printer->should_print(_method)) { + IdealGraphPrinter *printer = C->printer(); + if (printer && printer->should_print(1)) { char buffer[256]; sprintf(buffer, "Bytecode %d: %s", bci(), Bytecodes::name(bc())); bool old = printer->traverse_outs(); printer->set_traverse_outs(true); - printer->print_method(C, buffer, 4); + printer->print_method(buffer, 4); printer->set_traverse_outs(old); } #endif diff --git a/hotspot/src/share/vm/opto/runtime.cpp b/hotspot/src/share/vm/opto/runtime.cpp index 9bcc730ed9b..aae2cd0b9fa 100644 --- a/hotspot/src/share/vm/opto/runtime.cpp +++ b/hotspot/src/share/vm/opto/runtime.cpp @@ -159,9 +159,13 @@ address OptoRuntime::generate_stub( ciEnv* env, const char *name, int is_fancy_jump, bool pass_tls, bool save_argument_registers, - bool return_pc ) { + bool return_pc) { + + // Matching the default directive, we currently have no method to match. + DirectiveSet* directive = DirectivesStack::getDefaultDirective(CompileBroker::compiler(CompLevel_full_optimization)); ResourceMark rm; - Compile C( env, gen, C_function, name, is_fancy_jump, pass_tls, save_argument_registers, return_pc ); + Compile C( env, gen, C_function, name, is_fancy_jump, pass_tls, save_argument_registers, return_pc, directive); + DirectivesStack::release(directive); return C.stub_entry_point(); } diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp index 16f7c52801d..0d8e7303287 100644 --- a/hotspot/src/share/vm/opto/superword.cpp +++ b/hotspot/src/share/vm/opto/superword.cpp @@ -79,11 +79,12 @@ SuperWord::SuperWord(PhaseIdealLoop* phase) : #ifndef PRODUCT _vector_loop_debug = 0; if (_phase->C->method() != NULL) { - _phase->C->method()->has_option_value("VectorizeDebug", _vector_loop_debug); + _vector_loop_debug = phase->C->directive()->VectorizeDebugOption; } + _CountedLoopReserveKit_debug = 0; if (_phase->C->method() != NULL) { - _phase->C->method()->has_option_value("DoReserveCopyInSuperWordDebug", _CountedLoopReserveKit_debug); + _CountedLoopReserveKit_debug = phase->C->directive()->DoReserveCopyInSuperWordDebugOption; } #endif } diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 0e235f174c8..a5e50c23f9a 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -3840,7 +3840,9 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) { #if INCLUDE_ALL_GCS #include "gc/g1/heapRegionRemSet.hpp" #endif +#include "compiler/directivesParser.hpp" #include "memory/guardedMemory.hpp" +#include "utilities/json.hpp" #include "utilities/ostream.hpp" #include "utilities/quickSort.hpp" #if INCLUDE_VM_STRUCTS @@ -3903,6 +3905,8 @@ void execute_internal_vm_tests() { run_unit_test(ObjectMonitor::sanity_checks()); run_unit_test(Test_linked_list()); run_unit_test(TestChunkedList_test()); + run_unit_test(JSONTest::test()); + run_unit_test(DirectivesParser::test()); #if INCLUDE_VM_STRUCTS run_unit_test(VMStructs::test()); #endif diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index c930c549728..dfd715a5f12 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -551,14 +551,20 @@ WB_ENTRY(jboolean, WB_IsIntrinsicAvailable(JNIEnv* env, jobject o, jobject metho method_id = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION_(env, JNI_FALSE); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(method_id)); + + DirectiveSet* directive; if (compilation_context != NULL) { compilation_context_id = reflected_method_to_jmid(thread, env, compilation_context); CHECK_JNI_EXCEPTION_(env, JNI_FALSE); methodHandle cch(THREAD, Method::checked_resolve_jmethod_id(compilation_context_id)); - return CompileBroker::compiler(compLevel)->is_intrinsic_available(mh, cch); + directive = DirectivesStack::getMatchingDirective(cch, CompileBroker::compiler((int)compLevel)); } else { - return CompileBroker::compiler(compLevel)->is_intrinsic_available(mh, NULL); + // Calling with NULL matches default directive + directive = DirectivesStack::getDefaultDirective(CompileBroker::compiler((int)compLevel)); } + bool result = CompileBroker::compiler(compLevel)->is_intrinsic_available(mh, directive); + DirectivesStack::release(directive); + return result; WB_END WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject method, jboolean is_osr)) @@ -624,6 +630,47 @@ WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobjec return (mh->queued_for_compilation() || nm != NULL); WB_END +WB_ENTRY(jboolean, WB_ShouldPrintAssembly(JNIEnv* env, jobject o, jobject method)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION_(env, JNI_FALSE); + + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + DirectiveSet* directive = DirectivesStack::getMatchingDirective(mh, CompileBroker::compiler(CompLevel_simple)); + bool result = directive->PrintAssemblyOption; + DirectivesStack::release(directive); + + return result; +WB_END + +WB_ENTRY(jint, WB_MatchesInline(JNIEnv* env, jobject o, jobject method, jstring pattern)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION_(env, JNI_FALSE); + + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + + ResourceMark rm; + const char* error_msg = NULL; + char* method_str = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(pattern)); + InlineMatcher* m = InlineMatcher::parse_inline_pattern(method_str, error_msg); + + if (m == NULL) { + assert(error_msg != NULL, "Always have an error message"); + tty->print_cr("Got error: %s", error_msg); + return -1; // Pattern failed + } + + // Pattern works - now check if it matches + int result; + if (m->match(mh, InlineMatcher::force_inline)) { + result = 2; // Force inline match + } else if (m->match(mh, InlineMatcher::dont_inline)) { + result = 1; // Dont inline match + } else { + result = 0; // No match + } + delete m; + return result; +WB_END WB_ENTRY(jint, WB_MatchesMethod(JNIEnv* env, jobject o, jobject method, jstring pattern)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); @@ -1475,6 +1522,13 @@ static JNINativeMethod methods[] = { {CC"matchesMethod", CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)I", (void*)&WB_MatchesMethod}, + {CC"matchesInline", + CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)I", + (void*)&WB_MatchesInline}, + {CC"shouldPrintAssembly", + CC"(Ljava/lang/reflect/Executable;)Z", + (void*)&WB_ShouldPrintAssembly}, + {CC"isConstantVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsConstantVMFlag}, {CC"isLockedVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsLockedVMFlag}, {CC"setBooleanVMFlag", CC"(Ljava/lang/String;Z)V",(void*)&WB_SetBooleanVMFlag}, diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index c4572af5a5e..46557311d3d 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3650,6 +3650,9 @@ public: product(ccstr, CompileCommandFile, NULL, \ "Read compiler commands from this file [.hotspot_compiler]") \ \ + diagnostic(ccstr, CompilerDirectivesFile, NULL, \ + "Read compiler directives from this file") \ + \ product(ccstrlist, CompileCommand, "", \ "Prepend to .hotspot_compiler; e.g. log,java/lang/String.") \ \ @@ -4233,7 +4236,13 @@ public: "(3) no orphan methods exist for class C (i.e., methods for " \ "which the VM declares an intrinsic but that are not declared "\ "in the loaded class C. " \ - "Check (3) is available only in debug builds.") + "Check (3) is available only in debug builds.") \ + \ + diagnostic(bool, CompilerDirectivesIgnoreCompileCommands, false, \ + "Disable backwards compatibility for compile commands.") \ + \ + diagnostic(bool, PrintCompilerDirectives, false, \ + "Print compiler directives on installation.") /* * Macros for factoring of globals diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp index 8cf2f4ec5d2..e4d8fe241ac 100644 --- a/hotspot/src/share/vm/runtime/init.cpp +++ b/hotspot/src/share/vm/runtime/init.cpp @@ -71,7 +71,7 @@ void vmStructs_init(); void vtableStubs_init(); void InlineCacheBuffer_init(); void compilerOracle_init(); -void compileBroker_init(); +bool compileBroker_init(); // Initialization after compiler initialization bool universe_post_init(); // must happen after compiler_init @@ -131,7 +131,9 @@ jint init_globals() { vtableStubs_init(); InlineCacheBuffer_init(); compilerOracle_init(); - compileBroker_init(); + if (!compileBroker_init()) { + return JNI_EINVAL; + } VMRegImpl::set_regName(); if (!universe_post_init()) { diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index cea2360025d..3c8c4df149e 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -90,6 +90,7 @@ Monitor* CompileThread_lock = NULL; Monitor* Compilation_lock = NULL; Mutex* CompileTaskAlloc_lock = NULL; Mutex* CompileStatistics_lock = NULL; +Mutex* DirectivesStack_lock = NULL; Mutex* MultiArray_lock = NULL; Monitor* Terminator_lock = NULL; Monitor* BeforeExit_lock = NULL; @@ -264,6 +265,7 @@ void mutex_init() { def(CompiledIC_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // locks VtableStubs_lock, InlineCacheBuffer_lock def(CompileTaskAlloc_lock , Mutex , nonleaf+2, true, Monitor::_safepoint_check_always); def(CompileStatistics_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); + def(DirectivesStack_lock , Mutex , special, true, Monitor::_safepoint_check_never); def(MultiArray_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // locks SymbolTable_lock def(JvmtiThreadState_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // Used by JvmtiThreadState/JvmtiEventController diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index 715025b6c23..5f90aff1bb1 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp @@ -93,6 +93,7 @@ extern Monitor* CompileThread_lock; // a lock held by compile threa extern Monitor* Compilation_lock; // a lock used to pause compilation extern Mutex* CompileTaskAlloc_lock; // a lock held when CompileTasks are allocated extern Mutex* CompileStatistics_lock; // a lock held when updating compilation statistics +extern Mutex* DirectivesStack_lock; // a lock held when mutating the dirstack and ref counting directives extern Mutex* MultiArray_lock; // a lock used to guard allocation of multi-dim arrays extern Monitor* Terminator_lock; // a lock used to guard termination of the vm extern Monitor* BeforeExit_lock; // a lock used to guard cleanups and shutdown hooks diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index da2fe478f1d..231be768edf 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -2696,6 +2696,12 @@ void AdapterHandlerLibrary::create_native_wrapper(methodHandle method) { if (nm != NULL) { method->set_code(method, nm); + + DirectiveSet* directive = DirectivesStack::getDefaultDirective(CompileBroker::compiler(CompLevel_simple)); + if (directive->PrintAssemblyOption) { + Disassembler::decode(nm, tty); + } + DirectivesStack::release(directive); } } } // Unlock AdapterHandlerLibrary_lock diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp index a760ccb80cc..ff402e1eb58 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.cpp +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp @@ -28,7 +28,6 @@ #include "code/codeCache.hpp" #include "code/codeCacheExtensions.hpp" #include "compiler/compileBroker.hpp" -#include "compiler/compilerOracle.hpp" #include "gc/shared/isGCActiveMark.hpp" #include "memory/heapInspection.hpp" #include "memory/resourceArea.hpp" diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index 11a14889b68..1d9ddf4de4e 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -25,6 +25,8 @@ #include "precompiled.hpp" #include "classfile/classLoaderStats.hpp" #include "classfile/compactHashtable.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/directivesParser.hpp" #include "gc/shared/vmGCOperations.hpp" #include "oops/oop.inline.hpp" #include "runtime/globals.hpp" @@ -77,6 +79,11 @@ void DCmdRegistrant::register_dcmds(){ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + // Enhanced JMX Agent Support // These commands won't be exported via the DiagnosticCommandMBean until an // appropriate permission is created for them @@ -837,6 +844,38 @@ void CodeCacheDCmd::execute(DCmdSource source, TRAPS) { VMThread::execute(&printCodeCacheOp); } +void CompilerDirectivesPrintDCmd::execute(DCmdSource source, TRAPS) { + DirectivesStack::print(output()); +} + +CompilerDirectivesAddDCmd::CompilerDirectivesAddDCmd(outputStream* output, bool heap) : + DCmdWithParser(output, heap), + _filename("filename","Name of the directives file", "STRING",true) { + _dcmdparser.add_dcmd_argument(&_filename); +} + +void CompilerDirectivesAddDCmd::execute(DCmdSource source, TRAPS) { + DirectivesParser::parse_from_file(_filename.value(), output()); +} + +int CompilerDirectivesAddDCmd::num_arguments() { + ResourceMark rm; + CompilerDirectivesAddDCmd* dcmd = new CompilerDirectivesAddDCmd(NULL, false); + if (dcmd != NULL) { + DCmdMark mark(dcmd); + return dcmd->_dcmdparser.num_arguments(); + } else { + return 0; + } +} + +void CompilerDirectivesRemoveDCmd::execute(DCmdSource source, TRAPS) { + DirectivesStack::pop(); +} + +void CompilerDirectivesClearDCmd::execute(DCmdSource source, TRAPS) { + DirectivesStack::clear(); +} #if INCLUDE_SERVICES ClassHierarchyDCmd::ClassHierarchyDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp index 3106c0c9079..d71bff40bd4 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.hpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp @@ -613,4 +613,90 @@ public: virtual void execute(DCmdSource source, TRAPS); }; +class CompilerDirectivesPrintDCmd : public DCmd { +public: + CompilerDirectivesPrintDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} + static const char* name() { + return "Compiler.directives_print"; + } + static const char* description() { + return "Print all active compiler directives."; + } + static const char* impact() { + return "Low"; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments() { return 0; } + virtual void execute(DCmdSource source, TRAPS); +}; + +class CompilerDirectivesRemoveDCmd : public DCmd { +public: + CompilerDirectivesRemoveDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} + static const char* name() { + return "Compiler.directives_remove"; + } + static const char* description() { + return "Remove latest added compiler directive."; + } + static const char* impact() { + return "Low"; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments() { return 0; } + virtual void execute(DCmdSource source, TRAPS); +}; + +class CompilerDirectivesAddDCmd : public DCmdWithParser { +protected: + DCmdArgument _filename; +public: + CompilerDirectivesAddDCmd(outputStream* output, bool heap); + static const char* name() { + return "Compiler.directives_add"; + } + static const char* description() { + return "Add compiler directives from file."; + } + static const char* impact() { + return "Low"; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments(); + virtual void execute(DCmdSource source, TRAPS); +}; + +class CompilerDirectivesClearDCmd : public DCmd { +public: + CompilerDirectivesClearDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} + static const char* name() { + return "Compiler.directives_clear"; + } + static const char* description() { + return "Remove all compiler directives."; + } + static const char* impact() { + return "Low"; + } + static const JavaPermission permission() { + JavaPermission p = {"java.lang.management.ManagementPermission", + "monitor", NULL}; + return p; + } + static int num_arguments() { return 0; } + virtual void execute(DCmdSource source, TRAPS); +}; + #endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP diff --git a/hotspot/src/share/vm/shark/sharkCompiler.cpp b/hotspot/src/share/vm/shark/sharkCompiler.cpp index fe62efdecbd..e3188ce8fa9 100644 --- a/hotspot/src/share/vm/shark/sharkCompiler.cpp +++ b/hotspot/src/share/vm/shark/sharkCompiler.cpp @@ -145,7 +145,8 @@ void SharkCompiler::initialize() { void SharkCompiler::compile_method(ciEnv* env, ciMethod* target, - int entry_bci) { + int entry_bci, + DirectiveSet* directive) { assert(is_initialized(), "should be"); ResourceMark rm; const char *name = methodname( @@ -216,8 +217,8 @@ void SharkCompiler::compile_method(ciEnv* env, &handler_table, &inc_table, this, - env->comp_level(), false, + directive(), false); } diff --git a/hotspot/src/share/vm/shark/sharkCompiler.hpp b/hotspot/src/share/vm/shark/sharkCompiler.hpp index 1b8681771a0..0013e376c5e 100644 --- a/hotspot/src/share/vm/shark/sharkCompiler.hpp +++ b/hotspot/src/share/vm/shark/sharkCompiler.hpp @@ -30,6 +30,7 @@ #include "ci/ciMethod.hpp" #include "compiler/abstractCompiler.hpp" #include "compiler/compileBroker.hpp" +#include "compiler/compilerDirectives.hpp" #include "shark/llvmHeaders.hpp" #include "shark/sharkMemoryManager.hpp" @@ -54,7 +55,7 @@ class SharkCompiler : public AbstractCompiler { void initialize(); // Compile a normal (bytecode) method and install it in the VM - void compile_method(ciEnv* env, ciMethod* target, int entry_bci); + void compile_method(ciEnv* env, ciMethod* target, int entry_bci, DirectiveSet* dirset); // Print compilation timers and statistics void print_timers(); diff --git a/hotspot/src/share/vm/utilities/json.cpp b/hotspot/src/share/vm/utilities/json.cpp new file mode 100644 index 00000000000..e7df3d0de70 --- /dev/null +++ b/hotspot/src/share/vm/utilities/json.cpp @@ -0,0 +1,956 @@ +/* + * 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. + * + */ + +/* + * This is not really json in the state it is now. + * Some differences: + * - Double quotes around the key in an object is not enforced. + * i.e you can write: { foo : "bar" } instead of { "foo" : "bar" }. + * - Comments are allowed. + * - The last element in an object or array can have an ending comma. + */ + +#include "precompiled.hpp" +#include "utilities/json.hpp" +#include "utilities/ostream.hpp" +#include + +const char* strchrnul_(const char *s, int c) { + const char* tmp = strchr(s, c); + return tmp == NULL ? s + strlen(s) : tmp; +} + +JSON::JSON(const char* text, bool silent, outputStream* st) +: start(text), pos(text), mark(text), + level(0), line(1), column(0), silent(silent), _valid(true), _st(st) +{ +} + +void JSON::parse() { + assert(start != NULL, "Need something to parse"); + if (start == NULL) { + _valid = false; + error(INTERNAL_ERROR, "JSON parser was called with a string that was NULL."); + } else { + _valid = parse_json_value(); + } +} + +bool JSON::valid() { + return _valid; +} + +bool JSON::parse_json_value() { + int c; + + c = skip_to_token(); + if (c == -1) { + return false; + } + + // Must start with object or array + if (level == 0) { + + switch (c) { + case '{': + if (parse_json_object() == false) { + return false; + } + c = skip_to_token(); + if (c > 0) { + mark_pos(); + error(SYNTAX_ERROR, "Only one top level object/array is allowed."); + return false; + } else if (c < 0) { + return false; + } + return true; + + case '[': + if (parse_json_array() == false) { + return false; + } + c = skip_to_token(); + if (c > 0) { + mark_pos(); + error(SYNTAX_ERROR, "Only one top level object/array is allowed."); + return false; + } else if (c < 0) { + return false; + } + return true; + + case 0: + error(SYNTAX_ERROR, "EOS was encountered before any json declarations"); + return false; + + default: + error(SYNTAX_ERROR, "Json must start with an object or an array."); + return false; + } + } else { // level > 0 + switch (c) { + case '{': + return parse_json_object(); + + case '[': + return parse_json_array(); + + case '"': + return parse_json_string(); + + case '-': case '0': + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + return parse_json_number(); + + case 't': + return parse_json_symbol("true", JSON_TRUE); + + case 'f': + return parse_json_symbol("false", JSON_FALSE); + + case 'n': + return parse_json_symbol("null", JSON_NULL); + + case 0: + error(SYNTAX_ERROR, "EOS was encountered when expecting a json value."); + return false; + + default: + error(SYNTAX_ERROR, "Could not parse as a json value (did you forget to quote your strings?)."); + return false; + } + } +} + +// Should only be called when we actually have the start of an object +// Otherwise it is an internal error +bool JSON::parse_json_object() { + NOT_PRODUCT(const char* prev_pos); + int c; + + mark_pos(); + // Check that we are not called in error + if (expect_any("{", "object start", INTERNAL_ERROR) <= 0) { + return false; + } + + if (!callback(JSON_OBJECT_BEGIN, NULL, level++)) { + return false; + } + + for (;;) { + mark_pos(); + c = skip_to_token(); + if (c == 0) { + error(SYNTAX_ERROR, "EOS when expecting an object key or object end"); + return false; + } else if (c < 0) { + return false; + } else if (c == '}') { + // We got here from either empty object "{}" or ending comma "{a:1,}" + next(); + break; + } + + NOT_PRODUCT(prev_pos = pos); + if (parse_json_key() == false) { + return false; + } + assert(pos > prev_pos, "parsing stalled"); + + skip_to_token(); + mark_pos(); + if (expect_any(":", "object key-value separator") <= 0) { + return false; + } + + skip_to_token(); + mark_pos(); + NOT_PRODUCT(prev_pos = pos); + if (parse_json_value() == false) { + return false; + } + assert(pos > prev_pos, "parsing stalled"); + + c = skip_to_token(); + mark_pos(); + if (expect_any(",}", "value separator or object end") <= 0) { + return false; + } + if (c == '}') { + break; + } + } + + assert(c == '}', "array parsing ended without object end token ('}')"); + return callback(JSON_OBJECT_END, NULL, --level); +} + +// Should only be called when we actually have the start of an array +// Otherwise it is an internal error +bool JSON::parse_json_array() { + NOT_PRODUCT(const char* prev_pos); + int c; + + mark_pos(); + // Check that we are not called in error + if (expect_any("[", "array start character", INTERNAL_ERROR) <= 0) { + return false; + } + + if (!callback(JSON_ARRAY_BEGIN, NULL, level++)) { + return false; + } + + for (;;) { + mark_pos(); + c = skip_to_token(); + if (c == 0) { + error(SYNTAX_ERROR, "EOS when expecting a json value or array end"); + return false; + } else if (c < 0) { + return false; + } else if (c == ']') { + // We got here from either empty array "[]" or ending comma "[1,]" + next(); + break; + } + + mark_pos(); + NOT_PRODUCT(prev_pos = pos); + if (parse_json_value() == false) { + return false; + } + assert(pos > prev_pos, "parsing stalled"); + + c = skip_to_token(); + mark_pos(); + if (expect_any(",]", "value separator or array end") <= 0) { + return false; + } + if (c == ']') { + break; + } + } + + assert(c == ']', "array parsing ended without array end token (']')"); + return callback(JSON_ARRAY_END, NULL, --level); +} + +bool JSON::parse_json_string(bool key) { + const char* end; + JSON_VAL v; + + mark_pos(); + if (expect_any("\"", "string start character", INTERNAL_ERROR) <= 0) { + return false; + } + + end = strchr(pos, '"'); // TODO: escapes + if (end == NULL) { + error(SYNTAX_ERROR, "String started here never ended. Expected \'\"\' before EOS."); + return false; + } + + v.str.start = pos; + v.str.length = end - pos; + skip(end - pos); + + if (expect_any("\"", "string end character", INTERNAL_ERROR) <= 0) { + return false; + } + + if (key == true) { + return callback(JSON_KEY, &v, level); + } else { + return callback(JSON_STRING, &v, level); + } +} + +// TODO: hotspot equivalents? +static bool is_alpha(u_char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); +} +static bool is_numeric(u_char c) { + return (c >= '0' && c <= '9'); +} +static bool is_alnum(u_char c) { + return is_alpha(c) || is_numeric(c); +} +static bool is_word(u_char c) { + return c == '_' || is_alnum(c); +} + +// Allow object keys to be without quotation, +// but then restrict to ([a-zA-Z0-9_])+ +bool JSON::parse_json_key() { + const char* begin; + JSON_VAL v; + u_char c; + + mark_pos(); + c = peek(); + if (c == '"') { + return parse_json_string(true); + } + + begin = pos; + c = peek(); + if (c == 0) { + error(SYNTAX_ERROR, "Got EOS when expecting an object key."); + return false; + } else if (is_word(c) == false) { + error(SYNTAX_ERROR, "Expected an object key, which can be a double-quoted (\") string or a simple string (only alphanumeric characters and underscore, separated by whitespace) that doesn't need to be quoted."); + return false; + } + + for (;;) { + c = peek(); + // Allow the key to be delimited by control characters and the object key-value separator ':' + if (c <= ' ' || c == ':') { + break; + } else if (is_word(c) == false) { + error(SYNTAX_ERROR, "Object key need to be quoted, or consist entirely of alphanumeric characters and underscores."); + return false; + } + next(); + } + + v.str.start = begin; + v.str.length = pos - begin; + return callback(JSON_KEY, &v, level); +} + +bool JSON::parse_json_number() { + double double_value; + int tokens, read; + JSON_VAL v; + + mark_pos(); + + // Parsing number - for simplicity ints are limited to 2**53 + // sscanf as a double and check if part is 0. + tokens = sscanf(pos, "%lf%n", &double_value, &read); + assert(tokens <= 1, "scanf implementation that counts as a token, parsing json numbers will always fail"); + if (tokens == 1) { + assert(read > 0, "sanity"); + + if (floor(double_value) == double_value) { + // No exponent - treat as an int + v.int_value = (int)double_value; + if (!callback(JSON_NUMBER_INT, &v, level)) { + return false; + } + } else { + v.double_value = double_value; + if (!callback(JSON_NUMBER_FLOAT, &v, level)) { + return false; + } + } + skip(read); + return true; + } + + error(SYNTAX_ERROR, "Couldn't parse json number (note that exponents are not supported)."); + return false; +} + +bool JSON::parse_json_symbol(const char* name, JSON_TYPE symbol) { + if (expect_string(name, "maybe you forgot to quote your strings?") == false) { + mark_pos(); + return false; + } + return callback(symbol, NULL, level); +} + +void JSON::mark_pos() { + assert((mark == start || *(mark - 1)) != 0, "buffer overrun"); + assert(mark <= pos, "mark runahead"); + + u_char c; + + while (mark < pos) { + c = *mark; + assert(c != 0, "pos buffer overrun?"); + if (c != 0) { + mark++; + column++; + } + if (c == '\n') { + line++; + column = 0; + } + } + + assert(mark <= pos, "mark runahead"); +} + +u_char JSON::next() { + assert((pos == start || *(pos - 1)) != 0, "buffer overrun"); + + u_char c = *pos; + if (c != 0) { + pos++; + } + return c; +} + +u_char JSON::peek() { + return *pos; +} + +// Peek ahead i chars (0 is same as peek()) +u_char JSON::peek(size_t i) { + u_char c; + const char* p; + + p = pos; + c = *p; + while (i > 0 && c != 0) { + i--; + p++; + c = *p; + } + return c; +} + +/* + * Check that one of the expected characters is next in the stream. + * If not, it is an error. + * Returns 0 if EOS is encountered. + * Returns -1 if the next character was not one of the expected. + * Otherwise consumes and returns the expected character that was encountered. + */ +int JSON::expect_any(const char* valid_chars, const char* error_msg, JSON_ERROR e) { + size_t len; + u_char c; + + len = strlen(valid_chars); + assert(len > 0, "need non-empty string"); + + c = peek(); + if (c == 0) { + error(e, "Got EOS when expecting %s (%s\'%s\').", error_msg, len > 1 ? "one of " : "", valid_chars); + return 0; + } + for (size_t i = 0; i < len; i++) { + if (c == valid_chars[i]) { + return next(); + } + } + error(e, "Expected %s (%s\'%s\').", error_msg, len > 1 ? "one of " : "", valid_chars); + return -1; +} + +/* + * Check that the expected string is next in the stream. + * If not, it is an error. + * Consumes the expected characters if they are present. + * Returns true if the expected characters were present, otherwise false. + */ +bool JSON::expect_string(const char* expected_string, const char* error_msg, JSON_ERROR e) { + u_char c, expected_char; + size_t len; + + assert(expected_string != NULL, "need non-null string"); + len = strlen(expected_string); + assert(len > 0, "need non-empty string"); + + for (size_t i = 0; i < len; i++) { + expected_char = expected_string[i]; + assert(expected_char > ' ', "not sane for control characters"); + if (expected_char <= ' ') { + error(INTERNAL_ERROR, "expect got a control char"); + } + c = pos[i]; + if (c == 0) { + error(e, "EOS encountered when expecting %s (\"%s\")", error_msg, expected_string); + return false; + } else if (c != expected_char) { + error(e, "Expected \"%s\" (%s)", expected_string, error_msg); + return false; + } + } + skip(len); + return true; +} + +/* + * Skip i characters. + * Returns number of characters skipped. + */ +size_t JSON::skip(size_t i) { + u_char c; + size_t j; + + c = peek(); + for (j = i; c != 0 && j > 0; j--) { + c = next(); + } + return i - j; +} + +/* + * Skip whitespace and comments. + * Returns the first token after whitespace/comments without consuming it + * Returns 0 if EOS is encountered. + * Returns -1 if there is an error + */ +int JSON::skip_to_token() { + for (;;) { + int c = peek(0); + if (c == '/') { + u_char c2 = peek(1); + if (c2 == '/') { + c = skip_line_comment(); + } else if (c2 == '*') { + c = skip_block_comment(); + if (c < 0) { + return -1; + } + } + // Fall through to keep checking if there + // are more whitespace / comments to skip + } + if (c == 0 || c > ' ') { + return c; + } + next(); + } + return 0; +} + +/* + * Skip to, and return the wanted char without consuming it + * Returns 0 if EOS is encountered. + */ +u_char JSON::skip_to(u_char want) { + // We want the bookkeeping done in next(). + // Otherwise strchr could have been used. + u_char c; + for(;;) { + c = peek(); + if (c == 0 || c == want) { + return c; + } + next(); + } +} + +/* + * Should only be called when we actually have a line comment to skip. + * Otherwise it is an internal error. + * + * Will return the first token after the line comment without consuming it. + * Returns 0 if EOS is encoutered. + */ +u_char JSON::skip_line_comment() { + u_char c; + + // Check that we are not called in error + expect_any("/", "line comment start", INTERNAL_ERROR); + expect_any("/", "line comment start", INTERNAL_ERROR); + + c = skip_to('\n'); + if (c == 0) { + return 0; + } + next(); + return next(); +} + +/* + * Should only be called when we actually have a block comment to skip. + * Otherwise it is an internal error. + * + * Returns the first token after the block comment without consuming it. + * Returns -1 if EOS is encountered in the middle of a comment. + */ +int JSON::skip_block_comment() { + const char* current; + + // Check that we are not called in error. + if (peek() != '/' || peek(1) != '*') { + // Let expect handle EOS. + expect_string("/*", "block comment start", INTERNAL_ERROR); + return 0; + } + + current = pos; + for (;;) { + current = strchrnul_(current, '*'); + + if (current[0] == 0 || current[1] == 0) { + // Advance error marker to start of block comment + mark_pos(); + error(SYNTAX_ERROR, "Block comment started here never ended. Expected \"*/\" before EOS."); + return -1; + } + + if (current[1] == '/') { + pos = current; + if (expect_string("*/", "block comment end", INTERNAL_ERROR) == false) { + return -1; + } + // Found block comment end + return peek(); + } + current++; + } +} + +const char* JSON::strerror(JSON_ERROR e) { + switch (e) { + case SYNTAX_ERROR: + return "Syntax error"; + case INTERNAL_ERROR: + return "Internal error"; + case KEY_ERROR: + return "Key error"; + case VALUE_ERROR: + return "Value error"; + default: + ShouldNotReachHere(); + return "Unknown error"; + } +} + +void JSON::error(JSON_ERROR e, const char* format, ...) { + _valid = false; + + if (!silent) { + const char* line_start; + const char* tmp; + size_t line_length; + va_list args; + u_char c; + + _st->print("%s on line %u byte %u: ", JSON::strerror(e), line, column + 1); + va_start(args, format); + _st->vprint(format, args); + _st->cr(); + va_end(args); + + line_start = mark - column; + assert(line_start >= start, "out of bounds"); + assert(line_start <= mark, "out of bounds"); + assert(line_start == start || line_start[-1] == '\n', "line counting error"); + + c = *pos; + if (c == 0) { + _st->print(" Got "); + _st->print_cr("EOS."); + } + tmp = mark; + c = *tmp; + if (c > ' ') { + _st->print(" At "); + _st->print("'"); + while (c > ' ') { + _st->print("%c", c); + tmp++; + c = *tmp; + } + _st->print_cr("'."); + } + + // Skip to newline or EOS + tmp = strchrnul_(mark, '\n'); + line_length = tmp - line_start; + + _st->print_cr("%s", line_start); + } +} + +#ifndef PRODUCT +void JSONTest::test(const char* text, bool should_pass) { + JSONTest json(text); + if (should_pass) { + assert(json.valid() == true, "failed on a valid json string"); + if (VerboseInternalVMTests) { + tty->print_cr("-- json test passed as expected --"); + } + } else { + assert(json.valid() == false, "succeeded on an invalid json string"); + if (VerboseInternalVMTests) { + tty->print_cr("-- json test failed as expected --"); + } + } +} + +JSONTest::JSONTest(const char* text) : JSON(text, !VerboseInternalVMTests, tty) { + prev = JSON_NONE; + parse(); +} + +bool JSONTest::test() { + JSONTest::test("{}", true); + JSONTest::test("[]", true); + JSONTest::test(" { } ", true); + JSONTest::test(" [ ] ", true); + + JSONTest::test("\"error\"", false); + JSONTest::test("error", false); + JSONTest::test("1", false); + JSONTest::test("1.2", false); + JSONTest::test("true", false); + JSONTest::test("false", false); + JSONTest::test("null", false); + + JSONTest::test("[ 1 ]", true); + JSONTest::test("[ 1, ]", true); + JSONTest::test("[ true ]", true); + JSONTest::test("[ true, ]", true); + JSONTest::test("[ false ]", true); + JSONTest::test("[ false, ]", true); + JSONTest::test("[ null ]", true); + JSONTest::test("[ null, ]", true); + JSONTest::test("[ \"\" ]", true); + JSONTest::test("[ \"\", ]", true); + JSONTest::test("[ \"elem1\" ]", true); + JSONTest::test("[ \"elem1\", ]", true); + JSONTest::test("[ \"elem1\", ]", true); + JSONTest::test("[ \"elem1\" ]", true); + JSONTest::test("[ \"elem1\", \"elem2\" ]", true); + JSONTest::test("[ \"elem1\", \"elem2\", ]", true); + + + JSONTest::test("[ \"elem1\" ] { }", false); + JSONTest::test("[ elem1, \"elem2\" ]", false); + JSONTest::test("[ \"elem1\"", false); + JSONTest::test("[ \"elem1 ]", false); + JSONTest::test("[ \"elem1\", \"elem2\"", false); + JSONTest::test("[ truefoo ]", false); + JSONTest::test("[ falsefoo ]", false); + JSONTest::test("[ nullfoo ]", false); + + 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); + JSONTest::test("{ key : false, }", true); + JSONTest::test("{ key : null }", true); + JSONTest::test("{ key : null, }", true); + JSONTest::test("{ \"\" : \"\" }", true); + JSONTest::test("{ \"\" : \"\", }", true); + JSONTest::test("{ \"key1\" : \"val1\" }", true); + JSONTest::test("{ \"key1\" : \"val1\", }", true); + JSONTest::test("{ \"key1\" : \"val1\", \"key2\" : \"val2\" }", true); + JSONTest::test("{ \"key1\" : \"val1\", \"key2\" : \"val2\", }", true); + + JSONTest::test("{ \"key\" : \"val\" } [ \"error\" ]", false); + JSONTest::test("{ \"key\" : \"val\" ", false); + + JSONTest::test("/**/ { }", true); + JSONTest::test("/* */ { }", true); + JSONTest::test("/*foo*/ { }", true); + JSONTest::test("/* *foo */ { }", true); + JSONTest::test("/* *foo* */ { }", true); + JSONTest::test("/* /*foo */ { }", true); + JSONTest::test("{ } /* foo */", true); + JSONTest::test("{ } /* foo */ ", true); + JSONTest::test("{ } //", true); + JSONTest::test("{ } // ", true); + JSONTest::test("{ } // foo", true); + + JSONTest::test("/* * / { }", false); + JSONTest::test("/ * */ { }", false); + JSONTest::test("// { }", false); + JSONTest::test("/* { } */", false); + JSONTest::test("/* { } */ ", false); + JSONTest::test("/* { } ", false); + JSONTest::test("{ } /* ", false); + JSONTest::test("/* { } *", false); + JSONTest::test("{ /* } */", false); + JSONTest::test("[ /* ] */", false); + JSONTest::test("{ key : \"val\", /* } */", false); + JSONTest::test("[ \"val\", /* ] */", false); + + JSONTest::test("/* comment */{ key1 : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\", { \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\" : true }, \"key6\" : [ \"☃\" ], key7 : \"val\",}", true); + JSONTest::test("/* comment */ { \"key1\" : { \"key2\" : { \"key3\" : [ \"elem1\", \"elem2\", { \"key4\" : null }, 3 , 2 , 1 , 0 , -1 , -2 , -3 , true, false, null, ] }, \"key5\" : true }, \"key6\" : [ \"☃\" ], key7 : \"val\",}", true); + JSONTest::test("/*comment*/{\"ff1 fsd\":{\"☃\":{\"☃\":[\"☃\",\"☃\"]},\"☃\":true},\"☃\":[\"☃\"],\"foo\":\"☃\",}", true); + JSONTest::test("/* comment */ { key1 error : { \"☃\" : { \"☃\" : [ \"☃\", \"☃\" ] }, \"☃\" : true }, \"baz\" : [ \"☃\" ], foo : \"☃\",}", false); // first key needs to be quoted since it contains a space + + + JSONTest::test("[\n]", true); + + JSONTest::test( + "[" "\n" + " {" + " // pattern to match against class+method+signature" "\n" + " // leading and trailing wildcard (*) allowed" "\n" + " match: \"foo.bar.*\"," "\n" + " " "\n" + " // override defaults for specified compiler" "\n" + " // we may differentiate between levels too. TBD." "\n" + " c1: {" "\n" + " //override c1 presets " "\n" + " array_bounds_check_removal: false" "\n" + " }," "\n" + "" "\n" + " c2: {" "\n" + " // control inlining of method" "\n" + " // + force inline, - dont inline" "\n" + " inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n" + " }," "\n" + "" "\n" + " // directives outside a specific preset applies to all compilers" "\n" + " inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n" + " print_assembly: true," "\n" + " verify_oopmaps: true," "\n" + " max_loop_unrolling: 5" "\n" + " }," "\n" + " {" "\n" + " // matching several patterns require an array" "\n" + " match: [\"baz.*\",\"frob*\"]," "\n" + "" "\n" + " // only enable c1 for this directive" "\n" + " // all enabled by default. Command disables all not listed" "\n" + " enable: \"c1\"," "\n" + "" "\n" + " // applies to all compilers" "\n" + " // + force inline, - dont inline" "\n" + " inline : [ \"+java.util.*\", \"-com.sun.*\"]," "\n" + " print_inlining: true," "\n" + "" "\n" + " // force matching compiles to be blocking/syncronous" "\n" + " blocking_compile: true" "\n" + " }," "\n" + "]" "\n", true); + + return true; +} + +void JSONTest::log(uint indent, const char* format, ...) { + if (VerboseInternalVMTests) { + if (prev != JSON_KEY) { + for (uint i = 0; i < indent; i++) { + _st->print(" "); + } + } + va_list args; + va_start(args, format); + _st->vprint(format, args); + va_end(args); + } +} + +bool JSONTest::callback(JSON_TYPE t, JSON_VAL* v, uint rlevel) { + switch (t) { + case JSON_OBJECT_BEGIN: + log(rlevel, "{\n"); + prev = JSON_NONE; // Only care about JSON_KEY, to indent correctly + return true; + + case JSON_OBJECT_END: + log(rlevel, "},\n"); + prev = JSON_NONE; + return true; + + case JSON_ARRAY_BEGIN: + log(rlevel, "[\n"); + prev = JSON_NONE; + return true; + + case JSON_ARRAY_END: + log(rlevel, "],\n"); + prev = JSON_NONE; + return true; + + case JSON_KEY: + if (VerboseInternalVMTests) { + for (uint i = 0; i < rlevel; i++) { + _st->print(" "); + } + _st->print(""); + for (size_t i = 0; i < v->str.length; i++) { + u_char c = v->str.start[i]; + assert(c != 0, "string overrun"); + if (c == 0) { + return false; + } + _st->print("%c", c); + } + _st->print(" : "); + } + prev = JSON_KEY; + return true; + + case JSON_STRING: + if (VerboseInternalVMTests) { + if (prev != JSON_KEY) { + for (uint i = 0; i < rlevel; i++) { + _st->print(" "); + } + } + _st->print(""); + for (size_t i = 0; i < v->str.length; i++) { + u_char c = v->str.start[i]; + assert(c != 0, "string overrun"); + if (c == 0) { + return false; + } + _st->print("%c", c); + } + _st->print(",\n"); + } + prev = JSON_NONE; + return true; + + case JSON_NUMBER_INT: + log(rlevel, "%" PRId64 ",\n", v->int_value); + prev = JSON_NONE; + return true; + + case JSON_NUMBER_FLOAT: + log(rlevel, "%lf,\n", v->double_value); + prev = JSON_NONE; + return true; + + case JSON_TRUE: + log(rlevel, ",\n"); + prev = JSON_NONE; + return true; + + case JSON_FALSE: + log(rlevel, ",\n"); + prev = JSON_NONE; + return true; + + case JSON_NULL: + log(rlevel, ",\n"); + prev = JSON_NONE; + return true; + + default: + error(INTERNAL_ERROR, "unknown JSON type"); + return false; + } +} +#endif diff --git a/hotspot/src/share/vm/utilities/json.hpp b/hotspot/src/share/vm/utilities/json.hpp new file mode 100644 index 00000000000..b22eb427557 --- /dev/null +++ b/hotspot/src/share/vm/utilities/json.hpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_UTILITIES_JSON_HPP +#define SHARE_VM_UTILITIES_JSON_HPP + +#include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" + +class JSON : public ResourceObj { + protected: + JSON(const char* text, bool silent, outputStream* st); + void parse(); + bool valid(); + + typedef enum { + JSON_NONE, + JSON_OBJECT_BEGIN, + JSON_OBJECT_END, + JSON_ARRAY_BEGIN, + JSON_ARRAY_END, + JSON_KEY, + JSON_STRING, + JSON_NUMBER_INT, + JSON_NUMBER_FLOAT, + JSON_TRUE, + JSON_FALSE, + JSON_NULL + } JSON_TYPE; + + typedef union { + int64_t int_value; + double double_value; + + struct { + const char* start; + size_t length; + } str; + } JSON_VAL; + + typedef enum { + INTERNAL_ERROR, + SYNTAX_ERROR, + KEY_ERROR, + VALUE_ERROR + } JSON_ERROR; + + void error(JSON_ERROR e, const char* format, ...) ATTRIBUTE_PRINTF(3, 4); + outputStream* _st; + + private: + const char* start; + const char* pos; + + // For error printing + const char* mark; // Error marker + uint level; + uint line; + uint column; + + bool silent; + bool _valid; + + bool parse_json_value(); + bool parse_json_object(); + bool parse_json_array(); + bool parse_json_string(bool key = false); + bool parse_json_key(); + bool parse_json_number(); + bool parse_json_symbol(const char* name, JSON_TYPE symbol); + + virtual bool callback(JSON_TYPE t, JSON_VAL* v, uint level) = 0; + + void mark_pos(); + u_char next(); + u_char peek(); + u_char peek(size_t i); + int expect_any(const char* valid_chars, const char* error_msg, JSON_ERROR e = SYNTAX_ERROR); + bool expect_string(const char* expected_string, const char* error_msg = "", JSON_ERROR e = SYNTAX_ERROR); + size_t skip(size_t i); + int skip_to_token(); + u_char skip_to(u_char want); + u_char skip_line_comment(); + int skip_block_comment(); + + const char* strerror(JSON_ERROR e); +}; + +#ifndef PRODUCT +class JSONTest : public JSON { + public: + static bool test(); + + private: + JSONTest(const char* text); + static void test(const char* json, bool valid); + + void log(uint level, const char* format, ...) ATTRIBUTE_PRINTF(3, 4); + + bool callback(JSON_TYPE t, JSON_VAL* v, uint level); + JSON_TYPE prev; +}; +#endif + +#endif // SHARE_VM_UTILITIES_JSON_HPP diff --git a/hotspot/test/compiler/compilercontrol/InlineMatcherTest.java b/hotspot/test/compiler/compilercontrol/InlineMatcherTest.java new file mode 100644 index 00000000000..871f264baea --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/InlineMatcherTest.java @@ -0,0 +1,173 @@ +/* + * 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 InlineMatcherTest + * @bug 8074095 + * @library /testlibrary /../../test/lib + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI InlineMatcherTest + * @summary Testing of compiler/InlineMatcher + */ + +import java.lang.reflect.Method; +import java.util.ArrayList; +import sun.hotspot.WhiteBox; + +public class InlineMatcherTest { + + /** Instance of WhiteBox */ + protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + Method helper; + Method getDate; + Method inner; + Method toString; + + final public static int FORCE_INLINE = 2; + final public static int DONT_INLINE = 1; + final public static int NO_MATCH = 0; + final public static int PARSING_FAILURE = -1; + + public InlineMatcherTest() { + + } + + public void test() throws Exception { + // instantiate before calling getMethod on innerHelper + TestCases testCases = new TestCases(); + + helper = getMethod(InlineMatcherTest.class, "helper"); + + testCases.add(helper, "*.*", PARSING_FAILURE); + testCases.add(helper, "+*.*", FORCE_INLINE); + testCases.add(helper, "++*.*", NO_MATCH); // + is a valid part of the + // class name + testCases.add(helper, "-*.*", DONT_INLINE); + testCases.add(helper, "--*.*", NO_MATCH); // - is a valid part of the + // class name + + testCases.add(helper, "+InlineMatcherTest.*", FORCE_INLINE); + testCases.add(helper, "+InlineMatcherTest.helper", FORCE_INLINE); + testCases.add(helper, "+InlineMatcherTest.helper()", FORCE_INLINE); + testCases.add(helper, "+InlineMatcherTest.helper()V", FORCE_INLINE); + testCases.add(helper, "+InlineMatcherTest.helper(", FORCE_INLINE); + + testCases.add(helper, "-InlineMatcherTest.*", DONT_INLINE); + testCases.add(helper, "-InlineMatcherTest.helper", DONT_INLINE); + testCases.add(helper, "-InlineMatcherTest.helper()", DONT_INLINE); + testCases.add(helper, "-InlineMatcherTest.helper()V", DONT_INLINE); + testCases.add(helper, "-InlineMatcherTest.helper(", DONT_INLINE); + + testCases.add(helper, "+abc.*", NO_MATCH); + testCases.add(helper, "+*.abc", NO_MATCH); + testCases.add(helper, "-abc.*", NO_MATCH); + testCases.add(helper, "-*.abcls ", NO_MATCH); + + int failures = 0; + + for (TestCase t : testCases) { + System.out.println("Test case: " + t.pattern); + if (!t.test()) { + failures++; + System.out.println(" * FAILED"); + } + } + if (failures != 0) { + throw new Exception("There where " + failures + " failures in this test"); + } + } + + public static void main(String... args) throws Exception { + InlineMatcherTest test = new InlineMatcherTest(); + test.test(); + } + + public void helper() { + + } + + private static Method getMethod(Class klass, String name, Class... parameterTypes) { + try { + return klass.getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException("exception on getting method Helper." + name, e); + } + } + + class TestCase { + String pattern; + Method testTarget; + int expectedResult; + + public TestCase(Method testTarget, String pattern, int expectedResult) { + this.testTarget = testTarget; + this.pattern = pattern; + this.expectedResult = expectedResult; + } + + public String resultAsStr(int errorCode) { + switch (errorCode) { + case PARSING_FAILURE: + return "Parsing failed"; + case NO_MATCH: + return "No match"; + case DONT_INLINE: + return "Dont Inline"; + case FORCE_INLINE: + return "Force Inline"; + default: + return "Unknown error"; + } + } + + boolean test() { + int result = WHITE_BOX.matchesInline(testTarget, pattern); + if (result != expectedResult) { + System.out + .println("FAIL Wrong result, Got: " + resultAsStr(result) + "\n TestCase: " + this.toString()); + return false; + } + return true; + } + + @Override + public String toString() { + return "Method: '" + testTarget.toString() + "' Pattern: '" + pattern + "' Expected: " + + resultAsStr(expectedResult); + } + + public void innerHelper() { + + } + } + + class TestCases extends ArrayList { + private static final long serialVersionUID = 1L; + + public boolean add(Method testTarget, String pattern, int expectedResult) { + return super.add(new TestCase(testTarget, pattern, expectedResult)); + } + } +} diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java new file mode 100644 index 00000000000..a058b2b65c1 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java @@ -0,0 +1,125 @@ +/* + * 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 TestCompilerDirectivesCompatibilityBase + * @bug 8137167 + * @library /testlibrary /../../test/lib + * @modules java.base/sun.misc + * java.compiler + * java.management + * @build jdk.test.lib.* + * @build jdk.test.lib.dcmd.* + * @build sun.hotspot.WhiteBox.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityBase + * @summary Test compiler control compatibility with compile command + */ + +import jdk.test.lib.dcmd.CommandExecutor; +import jdk.test.lib.dcmd.JMXExecutor; + +import org.testng.annotations.Test; +import org.testng.Assert; + +import sun.hotspot.WhiteBox; + +import java.io.BufferedReader; +import java.io.File; +import java.io.StringReader; +import java.lang.reflect.Method; +import java.util.Objects; + +public class TestCompilerDirectivesCompatibilityBase { + + public static final WhiteBox WB = WhiteBox.getWhiteBox(); + public static String control_on, control_off; + Method method, nomatch; + + public void run(CommandExecutor executor) throws Exception { + + control_on = System.getProperty("test.src", ".") + File.separator + "control_on.txt"; + control_off = System.getProperty("test.src", ".") + File.separator + "control_off.txt"; + method = getMethod(TestCompilerDirectivesCompatibilityBase.class, "helper"); + nomatch = getMethod(TestCompilerDirectivesCompatibilityBase.class, "another"); + + testCompatibility(executor); + } + + public void testCompatibility(CommandExecutor executor) throws Exception { + + // Call all validation twice to catch error when overwriting a directive + // Flag is default off + expect(!WB.getBooleanVMFlag("PrintAssembly")); + expect(!WB.shouldPrintAssembly(method)); + expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method)); + expect(!WB.shouldPrintAssembly(nomatch)); + + // load directives that turn it on + executor.execute("Compiler.directives_add " + control_on); + expect(WB.shouldPrintAssembly(method)); + expect(!WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method)); + expect(!WB.shouldPrintAssembly(nomatch)); + + // remove and see that it is true again + executor.execute("Compiler.directives_remove"); + expect(!WB.shouldPrintAssembly(method)); + expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method)); + expect(!WB.shouldPrintAssembly(nomatch)); + } + + public void expect(boolean test) throws Exception { + if (!test) { + throw new Exception("Test failed"); + } + } + + public void expect(boolean test, String msg) throws Exception { + if (!test) { + throw new Exception(msg); + } + } + + @Test + public void jmx() throws Exception { + run(new JMXExecutor()); + } + + public void helper() { + } + + public void another() { + } + + public static Method getMethod(Class klass, String name, Class... parameterTypes) { + try { + return klass.getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException("exception on getting method Helper." + name, e); + } + } +} diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java new file mode 100644 index 00000000000..ab217789007 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.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. + */ + +/* + * @test TestCompilerDirectivesCompatibilityCommandOff + * @bug 8137167 + * @library /testlibrary /../../test/lib + * @modules java.base/sun.misc + * java.compiler + * java.management + * @build jdk.test.lib.* + * @build jdk.test.lib.dcmd.* + * @build sun.hotspot.WhiteBox.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -XX:-PrintAssembly -XX:CompileCommand=option,*.helper,bool,PrintAssembly,false -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityCommandOff + * @summary Test compiler control compatibility with compile command + */ + +// import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.dcmd.CommandExecutor; +import jdk.test.lib.dcmd.JMXExecutor; + +import org.testng.annotations.Test; +import org.testng.Assert; + +import sun.hotspot.WhiteBox; + +import java.io.BufferedReader; +import java.io.File; +import java.io.StringReader; +import java.lang.reflect.Method; +import java.util.Objects; + +public class TestCompilerDirectivesCompatibilityCommandOff extends TestCompilerDirectivesCompatibilityBase { + + public void testCompatibility(CommandExecutor executor) throws Exception { + + // Call all validation twice to catch error when overwriting a directive + // Flag is default off + expect(!WB.shouldPrintAssembly(method)); + expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method)); + expect(!WB.shouldPrintAssembly(nomatch)); + + // load directives that turn it on + executor.execute("Compiler.directives_add " + control_on); + expect(WB.shouldPrintAssembly(method)); + expect(!WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method)); + expect(!WB.shouldPrintAssembly(nomatch)); + + // remove and see that it is false again + executor.execute("Compiler.directives_remove"); + expect(!WB.shouldPrintAssembly(method)); + expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method)); + expect(!WB.shouldPrintAssembly(nomatch)); + } +} diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java new file mode 100644 index 00000000000..ea7689c7fc7 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.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. + */ + +/* + * @test TestCompilerDirectivesCompatibilityCommandOn + * @bug 8137167 + * @library /testlibrary /../../test/lib + * @modules java.base/sun.misc + * java.compiler + * java.management + * @build jdk.test.lib.* + * @build jdk.test.lib.dcmd.* + * @build sun.hotspot.WhiteBox.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -XX:-PrintAssembly -XX:CompileCommand=print,*.* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityCommandOn + * @summary Test compiler control compatibility with compile command + */ + +// import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.dcmd.CommandExecutor; +import jdk.test.lib.dcmd.JMXExecutor; + +import org.testng.annotations.Test; +import org.testng.Assert; + +import sun.hotspot.WhiteBox; + +import java.io.BufferedReader; +import java.io.File; +import java.io.StringReader; +import java.lang.reflect.Method; +import java.util.Objects; + +public class TestCompilerDirectivesCompatibilityCommandOn extends TestCompilerDirectivesCompatibilityBase{ + + public void testCompatibility(CommandExecutor executor) throws Exception { + + // Call all validation twice to catch error when overwriting a directive + // Flag is default on + expect(WB.shouldPrintAssembly(method)); + expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method)); + expect(WB.shouldPrintAssembly(nomatch)); + + // load directives that turn it off + executor.execute("Compiler.directives_add " + control_off); + expect(!WB.shouldPrintAssembly(method)); + expect(WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method)); + expect(WB.shouldPrintAssembly(nomatch)); + + // remove and see that it is true again + executor.execute("Compiler.directives_remove"); + expect(WB.shouldPrintAssembly(method)); + expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method)); + expect(WB.shouldPrintAssembly(nomatch)); + } +} diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java new file mode 100644 index 00000000000..0ec10ba45d3 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.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. + */ + +/* + * @test TestCompilerDirectivesCompatibilityFlag + * @bug 8137167 + * @library /testlibrary /../../test/lib + * @modules java.base/sun.misc + * java.compiler + * java.management + * @build jdk.test.lib.* + * @build jdk.test.lib.dcmd.* + * @build sun.hotspot.WhiteBox.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -XX:+PrintAssembly -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityFlag + * @summary Test compiler control compatibility with compile command + */ + +import jdk.test.lib.dcmd.CommandExecutor; +import jdk.test.lib.dcmd.JMXExecutor; + +import org.testng.annotations.Test; +import org.testng.Assert; + +import sun.hotspot.WhiteBox; + +import java.io.BufferedReader; +import java.io.File; +import java.io.StringReader; +import java.lang.reflect.Method; +import java.util.Objects; + +public class TestCompilerDirectivesCompatibilityFlag extends TestCompilerDirectivesCompatibilityBase { + + public void testCompatibility(CommandExecutor executor) throws Exception { + + // Call all validation twice to catch error when overwriting a directive + // Flag is default on + expect(WB.getBooleanVMFlag("PrintAssembly")); + expect(WB.shouldPrintAssembly(method)); + expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method)); + expect(WB.shouldPrintAssembly(nomatch)); + + // load directives that turn it off + executor.execute("Compiler.directives_add " + control_off); + expect(!WB.shouldPrintAssembly(method)); + expect(WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method)); + expect(WB.shouldPrintAssembly(nomatch)); + + // remove and see that it is true again + executor.execute("Compiler.directives_remove"); + expect(WB.shouldPrintAssembly(method)); + expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method)); + expect(WB.shouldPrintAssembly(nomatch)); + } +} diff --git a/hotspot/test/compiler/compilercontrol/control_off.txt b/hotspot/test/compiler/compilercontrol/control_off.txt new file mode 100644 index 00000000000..2eec82b3d34 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/control_off.txt @@ -0,0 +1,7 @@ +[ + { + match: "*.helper", + PrintAssembly: false, + DisableIntrinsic:"x" + } +] diff --git a/hotspot/test/compiler/compilercontrol/control_on.txt b/hotspot/test/compiler/compilercontrol/control_on.txt new file mode 100644 index 00000000000..c2883c1992c --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/control_on.txt @@ -0,0 +1,7 @@ +[ + { + match: "*.helper", + PrintAssembly: true, + DisableIntrinsic:"_dsin" + } +] diff --git a/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java b/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java new file mode 100644 index 00000000000..770373e3f82 --- /dev/null +++ b/hotspot/test/serviceability/dcmd/compiler/CompilerDirectivesDCMDTest.java @@ -0,0 +1,158 @@ +/* + * 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 CompilerDirectivesDCMDTest + * @bug 8137167 + * @library /testlibrary + * @modules java.base/sun.misc + * java.compiler + * java.management + * @build jdk.test.lib.* + * @build jdk.test.lib.dcmd.* + * @run main ClassFileInstaller jdk.test.lib.Platform + * @run testng/othervm CompilerDirectivesDCMDTest + * @summary Test of diagnostic command + */ + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.dcmd.CommandExecutor; +import jdk.test.lib.dcmd.JMXExecutor; +import jdk.test.lib.Platform; +import org.testng.annotations.Test; +import org.testng.Assert; + +import java.io.BufferedReader; +import java.io.File; +import java.io.StringReader; + +public class CompilerDirectivesDCMDTest { + + public static String filename; + + public void run(CommandExecutor executor) { + + if (Platform.isServer()) { + filename = System.getProperty("test.src", ".") + File.separator + "control2.txt"; + } else { + filename = System.getProperty("test.src", ".") + File.separator + "control1.txt"; + } + testPrintCommand(executor); + testAddAndRemoveCommand(executor); + } + + public static void testPrintCommand(CommandExecutor executor) { + + // Get output from dcmd (diagnostic command) + OutputAnalyzer output = executor.execute("Compiler.directives_print"); + int count = find(output, "Directive:"); + if (count < 1) { + Assert.fail("Expected at least one directive - found " + count); + } + } + + public static void testAddAndRemoveCommand(CommandExecutor executor) { + OutputAnalyzer output; + int count = 0; + + // Start with clearing stack - expect only default directive left + output = executor.execute("Compiler.directives_clear"); + output = executor.execute("Compiler.directives_print"); + count = find(output, "Directive:"); + if (count != 1) { + Assert.fail("Expected one directives - found " + count); + } + + // Test that we can not remove the default directive + output = executor.execute("Compiler.directives_remove"); + output = executor.execute("Compiler.directives_print"); + count = find(output, "Directive:"); + if (count != 1) { + Assert.fail("Expected one directives - found " + count); + } + + // Test adding some directives from file + output = executor.execute("Compiler.directives_add " + filename); + output = executor.execute("Compiler.directives_print"); + count = find(output, "Directive:"); + if (count != 3) { + Assert.fail("Expected three directives - found " + count); + } + + // Test remove one directive + output = executor.execute("Compiler.directives_remove"); + output = executor.execute("Compiler.directives_print"); + count = find(output, "Directive:"); + if (count != 2) { + Assert.fail("Expected two directives - found " + count); + } + + // Test adding directives again + output = executor.execute("Compiler.directives_add " + filename); + output = executor.execute("Compiler.directives_print"); + count = find(output, "Directive:"); + if (count != 4) { + Assert.fail("Expected four directives - found " + count); + } + + // Test clearing + output = executor.execute("Compiler.directives_clear"); + output = executor.execute("Compiler.directives_print"); + count = find(output, "Directive:"); + if (count != 1) { + Assert.fail("Expected one directives - found " + count); + } + + // Test clear when already cleared + output = executor.execute("Compiler.directives_clear"); + output = executor.execute("Compiler.directives_print"); + count = find(output, "Directive:"); + if (count != 1) { + Assert.fail("Expected one directives - found " + count); + } + + // Test remove one directive when empty + output = executor.execute("Compiler.directives_remove"); + output = executor.execute("Compiler.directives_print"); + count = find(output, "Directive:"); + if (count != 1) { + Assert.fail("Expected one directive - found " + count); + } + } + + public static int find(OutputAnalyzer output, String find) { + int count = 0; + + for (String line : output.asLines()) { + if (line.startsWith(find)) { + count++; + } + } + return count; + } + + @Test + public void jmx() { + run(new JMXExecutor()); + } +} diff --git a/hotspot/test/serviceability/dcmd/compiler/control1.txt b/hotspot/test/serviceability/dcmd/compiler/control1.txt new file mode 100644 index 00000000000..b0992b1499f --- /dev/null +++ b/hotspot/test/serviceability/dcmd/compiler/control1.txt @@ -0,0 +1,17 @@ +[ + { + match: "foo/bar.*", + PrintAssembly: false, + c1: { + BreakAtExecute: false, + }, + inline : [ "+javax/util.*", "-comx/sun.*"], + PrintAssembly: false, + }, + { + match: ["baz.*","frob.*"], + inline : [ "+java/util.*", "-com/sun.*" ], + PrintAssembly: false, + BreakAtExecute: false, + } +] diff --git a/hotspot/test/serviceability/dcmd/compiler/control2.txt b/hotspot/test/serviceability/dcmd/compiler/control2.txt new file mode 100644 index 00000000000..03a32cf91e9 --- /dev/null +++ b/hotspot/test/serviceability/dcmd/compiler/control2.txt @@ -0,0 +1,22 @@ +[ + { + match: "foo/bar.*", + PrintAssembly: false, + c1: { + BreakAtExecute: false, + }, + c2: { + inline : "+java/util.*", + BreakAtCompile: true + }, + inline : [ "+javax/util.*", "-comx/sun.*"], + PrintAssembly: false, + IGVPrintLevel: 2 + }, + { + match: ["baz.*","frob.*"], + inline : [ "+java/util.*", "-com/sun.*" ], + PrintAssembly: false, + BreakAtExecute: false, + } +] From deec4ce18c8c2f64a9cb549d5eb870fa0ee32937 Mon Sep 17 00:00:00 2001 From: Vladimir Ivanov Date: Tue, 20 Oct 2015 19:22:56 +0300 Subject: [PATCH 17/75] 8132168: Support IdealGraphVisualizer in optimized build Reviewed-by: kvn --- hotspot/src/share/vm/opto/c2_globals.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/opto/c2_globals.hpp b/hotspot/src/share/vm/opto/c2_globals.hpp index 1782abfd0a1..864f9d859e4 100644 --- a/hotspot/src/share/vm/opto/c2_globals.hpp +++ b/hotspot/src/share/vm/opto/c2_globals.hpp @@ -368,18 +368,18 @@ product(bool, UseRDPCForConstantTableBase, false, \ "Use Sparc RDPC instruction for the constant table base.") \ \ - develop(bool, PrintIdealGraph, false, \ + notproduct(bool, PrintIdealGraph, false, \ "Print ideal graph to XML file / network interface. " \ "By default attempts to connect to the visualizer on a socket.") \ \ - develop(intx, PrintIdealGraphLevel, 0, \ + notproduct(intx, PrintIdealGraphLevel, 0, \ "Level of detail of the ideal graph printout. " \ "System-wide value, 0=nothing is printed, 4=all details printed. "\ "Level of detail of printouts can be set on a per-method level " \ "as well by using CompileCommand=option.") \ range(0, 4) \ \ - develop(intx, PrintIdealGraphPort, 4444, \ + notproduct(intx, PrintIdealGraphPort, 4444, \ "Ideal graph printer to network port") \ range(0, SHRT_MAX) \ \ From 0ea5332014bc2cf772f6d790759f2af7fba45b62 Mon Sep 17 00:00:00 2001 From: Pavel Punegov Date: Tue, 20 Oct 2015 21:09:57 +0300 Subject: [PATCH 18/75] 8066153: JEP-JDK-8046155: Test task: cover existing Tests for CompilerCommand and CompilerControl's directives Reviewed-by: kvn --- .../commandfile/CompileOnlyTest.java | 46 +++ .../commandfile/ExcludeTest.java | 46 +++ .../compilercontrol/commandfile/LogTest.java | 46 +++ .../commandfile/PrintTest.java | 46 +++ .../commands/CompileOnlyTest.java | 46 +++ .../compilercontrol/commands/ExcludeTest.java | 46 +++ .../compilercontrol/commands/LogTest.java | 46 +++ .../compilercontrol/commands/PrintTest.java | 46 +++ .../directives/CompileOnlyTest.java | 47 +++ .../directives/ExcludeTest.java | 46 +++ .../compilercontrol/directives/LogTest.java | 46 +++ .../compilercontrol/directives/PrintTest.java | 46 +++ .../mixed/RandomCommandsTest.java | 44 +++ .../mixed/RandomValidCommandsTest.java | 44 +++ .../share/AbstractTestBase.java | 60 ++++ .../compilercontrol/share/JSONFile.java | 189 ++++++++++++ .../compilercontrol/share/MultiCommand.java | 82 ++++++ .../compilercontrol/share/SingleCommand.java | 57 ++++ .../share/actions/BaseAction.java | 123 ++++++++ .../share/actions/CompileAction.java | 108 +++++++ .../share/method/MethodGenerator.java | 17 ++ .../share/method/SignatureType.java | 12 +- .../share/processors/CommandProcessor.java | 62 ++++ .../share/processors/LogProcessor.java | 133 +++++++++ .../share/processors/PrintProcessor.java | 115 ++++++++ .../share/processors/QuietProcessor.java | 59 ++++ .../scenario/AbstractCommandBuilder.java | 95 ++++++ .../share/scenario/Command.java | 69 +++++ .../share/scenario/CommandFileBuilder.java | 59 ++++ .../share/scenario/CommandGenerator.java | 102 +++++++ .../share/scenario/CommandOptionsBuilder.java | 44 +++ .../share/scenario/CompileCommand.java | 66 +++++ .../share/scenario/DirectiveBuilder.java | 236 +++++++++++++++ .../share/scenario/DirectiveWriter.java | 187 ++++++++++++ .../share/scenario/Scenario.java | 272 ++++++++++++++++++ 35 files changed, 2787 insertions(+), 1 deletion(-) create mode 100644 hotspot/test/compiler/compilercontrol/commandfile/CompileOnlyTest.java create mode 100644 hotspot/test/compiler/compilercontrol/commandfile/ExcludeTest.java create mode 100644 hotspot/test/compiler/compilercontrol/commandfile/LogTest.java create mode 100644 hotspot/test/compiler/compilercontrol/commandfile/PrintTest.java create mode 100644 hotspot/test/compiler/compilercontrol/commands/CompileOnlyTest.java create mode 100644 hotspot/test/compiler/compilercontrol/commands/ExcludeTest.java create mode 100644 hotspot/test/compiler/compilercontrol/commands/LogTest.java create mode 100644 hotspot/test/compiler/compilercontrol/commands/PrintTest.java create mode 100644 hotspot/test/compiler/compilercontrol/directives/CompileOnlyTest.java create mode 100644 hotspot/test/compiler/compilercontrol/directives/ExcludeTest.java create mode 100644 hotspot/test/compiler/compilercontrol/directives/LogTest.java create mode 100644 hotspot/test/compiler/compilercontrol/directives/PrintTest.java create mode 100644 hotspot/test/compiler/compilercontrol/mixed/RandomCommandsTest.java create mode 100644 hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java create mode 100644 hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java create mode 100644 hotspot/test/compiler/compilercontrol/share/JSONFile.java create mode 100644 hotspot/test/compiler/compilercontrol/share/MultiCommand.java create mode 100644 hotspot/test/compiler/compilercontrol/share/SingleCommand.java create mode 100644 hotspot/test/compiler/compilercontrol/share/actions/BaseAction.java create mode 100644 hotspot/test/compiler/compilercontrol/share/actions/CompileAction.java create mode 100644 hotspot/test/compiler/compilercontrol/share/processors/CommandProcessor.java create mode 100644 hotspot/test/compiler/compilercontrol/share/processors/LogProcessor.java create mode 100644 hotspot/test/compiler/compilercontrol/share/processors/PrintProcessor.java create mode 100644 hotspot/test/compiler/compilercontrol/share/processors/QuietProcessor.java create mode 100644 hotspot/test/compiler/compilercontrol/share/scenario/AbstractCommandBuilder.java create mode 100644 hotspot/test/compiler/compilercontrol/share/scenario/Command.java create mode 100644 hotspot/test/compiler/compilercontrol/share/scenario/CommandFileBuilder.java create mode 100644 hotspot/test/compiler/compilercontrol/share/scenario/CommandGenerator.java create mode 100644 hotspot/test/compiler/compilercontrol/share/scenario/CommandOptionsBuilder.java create mode 100644 hotspot/test/compiler/compilercontrol/share/scenario/CompileCommand.java create mode 100644 hotspot/test/compiler/compilercontrol/share/scenario/DirectiveBuilder.java create mode 100644 hotspot/test/compiler/compilercontrol/share/scenario/DirectiveWriter.java create mode 100644 hotspot/test/compiler/compilercontrol/share/scenario/Scenario.java diff --git a/hotspot/test/compiler/compilercontrol/commandfile/CompileOnlyTest.java b/hotspot/test/compiler/compilercontrol/commandfile/CompileOnlyTest.java new file mode 100644 index 00000000000..87a5efd732e --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/commandfile/CompileOnlyTest.java @@ -0,0 +1,46 @@ +/* + * 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 8137167 + * @summary Tests CompileCommand=compileonly + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build CompileOnlyTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm compiler.compilercontrol.commandfile.CompileOnlyTest + */ + +package compiler.compilercontrol.commandfile; + +import compiler.compilercontrol.share.SingleCommand; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.Scenario; + +public class CompileOnlyTest { + public static void main(String[] args) { + new SingleCommand(Command.COMPILEONLY, Scenario.Type.FILE).test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/commandfile/ExcludeTest.java b/hotspot/test/compiler/compilercontrol/commandfile/ExcludeTest.java new file mode 100644 index 00000000000..b4843a7d930 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/commandfile/ExcludeTest.java @@ -0,0 +1,46 @@ +/* + * 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 8137167 + * @summary Tests CompileCommand=exclude + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build ExcludeTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm compiler.compilercontrol.commands.ExcludeTest + */ + +package compiler.compilercontrol.commandfile; + +import compiler.compilercontrol.share.SingleCommand; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.Scenario; + +public class ExcludeTest { + public static void main(String[] args) { + new SingleCommand(Command.EXCLUDE, Scenario.Type.FILE).test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/commandfile/LogTest.java b/hotspot/test/compiler/compilercontrol/commandfile/LogTest.java new file mode 100644 index 00000000000..60463073253 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/commandfile/LogTest.java @@ -0,0 +1,46 @@ +/* + * 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 8137167 + * @summary Tests CompileCommand=log + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build LogTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm compiler.compilercontrol.commandfile.LogTest + */ + +package compiler.compilercontrol.commandfile; + +import compiler.compilercontrol.share.SingleCommand; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.Scenario; + +public class LogTest { + public static void main(String[] args) { + new SingleCommand(Command.LOG, Scenario.Type.FILE).test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/commandfile/PrintTest.java b/hotspot/test/compiler/compilercontrol/commandfile/PrintTest.java new file mode 100644 index 00000000000..2040b4aaac8 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/commandfile/PrintTest.java @@ -0,0 +1,46 @@ +/* + * 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 8137167 + * @summary Tests CompileCommand=print + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build PrintTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm compiler.compilercontrol.commandfile.PrintTest + */ + +package compiler.compilercontrol.commandfile; + +import compiler.compilercontrol.share.SingleCommand; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.Scenario; + +public class PrintTest { + public static void main(String[] args) { + new SingleCommand(Command.PRINT, Scenario.Type.FILE).test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/commands/CompileOnlyTest.java b/hotspot/test/compiler/compilercontrol/commands/CompileOnlyTest.java new file mode 100644 index 00000000000..ad4328fc018 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/commands/CompileOnlyTest.java @@ -0,0 +1,46 @@ +/* + * 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 8137167 + * @summary Tests CompileCommand=compileonly + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build CompileOnlyTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm compiler.compilercontrol.commands.CompileOnlyTest + */ + +package compiler.compilercontrol.commands; + +import compiler.compilercontrol.share.SingleCommand; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.Scenario; + +public class CompileOnlyTest { + public static void main(String[] args) { + new SingleCommand(Command.COMPILEONLY, Scenario.Type.OPTION).test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/commands/ExcludeTest.java b/hotspot/test/compiler/compilercontrol/commands/ExcludeTest.java new file mode 100644 index 00000000000..4be5f37998f --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/commands/ExcludeTest.java @@ -0,0 +1,46 @@ +/* + * 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 8137167 + * @summary Tests CompileCommand=exclude + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build ExcludeTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm compiler.compilercontrol.commands.ExcludeTest + */ + +package compiler.compilercontrol.commands; + +import compiler.compilercontrol.share.SingleCommand; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.Scenario; + +public class ExcludeTest { + public static void main(String[] args) { + new SingleCommand(Command.EXCLUDE, Scenario.Type.OPTION).test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/commands/LogTest.java b/hotspot/test/compiler/compilercontrol/commands/LogTest.java new file mode 100644 index 00000000000..2b28436ed1a --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/commands/LogTest.java @@ -0,0 +1,46 @@ +/* + * 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 8137167 + * @summary Tests CompileCommand=log + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build LogTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm compiler.compilercontrol.commands.LogTest + */ + +package compiler.compilercontrol.commands; + +import compiler.compilercontrol.share.SingleCommand; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.Scenario; + +public class LogTest { + public static void main(String[] args) { + new SingleCommand(Command.LOG, Scenario.Type.OPTION).test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/commands/PrintTest.java b/hotspot/test/compiler/compilercontrol/commands/PrintTest.java new file mode 100644 index 00000000000..62af5e0552b --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/commands/PrintTest.java @@ -0,0 +1,46 @@ +/* + * 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 8137167 + * @summary Tests CompileCommand=print + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build PrintTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm compiler.compilercontrol.commands.PrintTest + */ + +package compiler.compilercontrol.commands; + +import compiler.compilercontrol.share.SingleCommand; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.Scenario; + +public class PrintTest { + public static void main(String[] args) { + new SingleCommand(Command.PRINT, Scenario.Type.OPTION).test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/directives/CompileOnlyTest.java b/hotspot/test/compiler/compilercontrol/directives/CompileOnlyTest.java new file mode 100644 index 00000000000..12a522d777b --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/directives/CompileOnlyTest.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. + */ + +/* + * @test + * @bug 8137167 + * @summary Tests directives to be able to compile only specified methods + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build CompileOnlyTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm compiler.compilercontrol.directives.CompileOnlyTest + */ + +package compiler.compilercontrol.directives; + +import compiler.compilercontrol.share.SingleCommand; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.Scenario; + +public class CompileOnlyTest { + public static void main(String[] args) { + new SingleCommand(Command.COMPILEONLY, Scenario.Type.DIRECTIVE) + .test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/directives/ExcludeTest.java b/hotspot/test/compiler/compilercontrol/directives/ExcludeTest.java new file mode 100644 index 00000000000..cd6d01c65a1 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/directives/ExcludeTest.java @@ -0,0 +1,46 @@ +/* + * 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 8137167 + * @summary Tests directives to be able to exclude methods from compilation + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build ExcludeTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm compiler.compilercontrol.directives.ExcludeTest + */ + +package compiler.compilercontrol.directives; + +import compiler.compilercontrol.share.SingleCommand; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.Scenario; + +public class ExcludeTest { + public static void main(String[] args) { + new SingleCommand(Command.EXCLUDE, Scenario.Type.DIRECTIVE).test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/directives/LogTest.java b/hotspot/test/compiler/compilercontrol/directives/LogTest.java new file mode 100644 index 00000000000..cca0b7e6754 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/directives/LogTest.java @@ -0,0 +1,46 @@ +/* + * 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 8137167 + * @summary Tests directives to be able to turn on LogCompilation + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build LogTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm compiler.compilercontrol.directives.LogTest + */ + +package compiler.compilercontrol.directives; + +import compiler.compilercontrol.share.SingleCommand; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.Scenario; + +public class LogTest { + public static void main(String[] args) { + new SingleCommand(Command.LOG, Scenario.Type.DIRECTIVE).test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/directives/PrintTest.java b/hotspot/test/compiler/compilercontrol/directives/PrintTest.java new file mode 100644 index 00000000000..466f452f48c --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/directives/PrintTest.java @@ -0,0 +1,46 @@ +/* + * 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 8137167 + * @summary Tests directives to be able to turn on print_assembly + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build PrintTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm compiler.compilercontrol.directives.PrintTest + */ + +package compiler.compilercontrol.directives; + +import compiler.compilercontrol.share.SingleCommand; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.Scenario; + +public class PrintTest { + public static void main(String[] args) { + new SingleCommand(Command.PRINT, Scenario.Type.DIRECTIVE).test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/mixed/RandomCommandsTest.java b/hotspot/test/compiler/compilercontrol/mixed/RandomCommandsTest.java new file mode 100644 index 00000000000..7837b16d480 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/mixed/RandomCommandsTest.java @@ -0,0 +1,44 @@ +/* + * 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 8137167 + * @summary Randomly generates commands with random types + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build RandomCommandsTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm/timeout=600 compiler.compilercontrol.mixed.RandomCommandsTest + */ + +package compiler.compilercontrol.mixed; + +import compiler.compilercontrol.share.MultiCommand; + +public class RandomCommandsTest { + public static void main(String[] args) { + MultiCommand.generateRandomTest(false).test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java b/hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java new file mode 100644 index 00000000000..951789991f7 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java @@ -0,0 +1,44 @@ +/* + * 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 8137167 + * @summary Randomly generates valid commands with random types + * @library /testlibrary /../../test/lib /compiler/testlibrary ../share / + * @build RandomValidCommandsTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.* + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm/timeout=600 compiler.compilercontrol.mixed.RandomValidCommandsTest + */ + +package compiler.compilercontrol.mixed; + +import compiler.compilercontrol.share.MultiCommand; + +public class RandomValidCommandsTest { + public static void main(String[] args) { + MultiCommand.generateRandomTest(true).test(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java b/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java new file mode 100644 index 00000000000..2e1c2013b43 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java @@ -0,0 +1,60 @@ +/* + * 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.compilercontrol.share; + +import compiler.compilercontrol.share.method.MethodDescriptor; +import compiler.compilercontrol.share.method.MethodGenerator; +import jdk.test.lib.Pair; +import pool.PoolHelper; + +import java.lang.reflect.Executable; +import java.util.List; +import java.util.concurrent.Callable; + +public abstract class AbstractTestBase { + protected static final MethodGenerator METHOD_GEN = new MethodGenerator(); + protected static final int ATTEMPTS = 25; + protected static final List>> METHODS + = new PoolHelper().getAllMethods(PoolHelper.METHOD_FILTER); + + public abstract void test(); + + /** + * Generate random valid method descriptor + * + * @param exec method to make descriptor for + * @return a valid {@link MethodDescriptor#isValid()} descriptor instance + */ + public static MethodDescriptor getValidMethodDescriptor(Executable exec) { + MethodDescriptor md = METHOD_GEN.generateRandomDescriptor(exec); + for (int i = 0; !md.isValid() && i < ATTEMPTS; i++) { + md = METHOD_GEN.generateRandomDescriptor(exec); + } + if (!md.isValid()) { + System.out.println("WARN: Using predefined pattern"); + md = MethodGenerator.commandDescriptor(exec); + } + return md; + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/JSONFile.java b/hotspot/test/compiler/compilercontrol/share/JSONFile.java new file mode 100644 index 00000000000..6d22d898e7c --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/JSONFile.java @@ -0,0 +1,189 @@ +/* + * 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.compilercontrol.share; + +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.util.Objects; +import java.util.Stack; + +/** + * Simple JSON file writer + */ +public class JSONFile implements AutoCloseable { + private final Stack stack; + private final String fileName; + private final PrintStream out; + private int spaces; + + /** + * JSON element + */ + public enum Element { + OBJECT, + ARRAY, + PAIR, + VALUE + } + + /** + * Constructor. Creates file with default name + */ + public JSONFile() { + this("directives_file.json"); + } + + /** + * Constructor + * + * @param fileName file name + */ + public JSONFile(String fileName) { + this.spaces = 0; + this.stack = new Stack<>(); + this.fileName = fileName; + try { + out = new PrintStream(fileName); + } catch (FileNotFoundException e) { + throw new Error("TESTBUG: can't open/create file " + fileName, e); + } + } + + /** + * Gets file name + * + * @return file name string + */ + public String getFileName() { + return fileName; + } + + /** + * Gets current JSON element in the file. + * The element is a current {@linkplain Element} + * that was written into a file. + * + * @return the type of the current element, + * or null if there are nothing written + */ + public Element getElement() { + if (stack.empty()) { + return null; + } + return stack.peek(); + } + + /** + * Writes given type with a value to file. + * Note that only PAIR and VALUE types accept a single value parameter. + * OBJECT and ARRAY do not have a value + * + * @param element JSON element type + * @param value element's value + * @return this file instance + */ + public JSONFile write(Element element, String... value) { + if (value.length > 1) { + throw new Error("TESTBUG: Unexpected value length: " + + value.length); + } + if (!stack.empty()) { + if (stack.peek() == Element.VALUE) { + out.print(", "); + stack.pop(); + } + } + switch (element) { + case OBJECT: + out.print("{"); + spaces++; + stack.push(Element.VALUE); + break; + case ARRAY: + out.print("["); + stack.push(Element.VALUE); + break; + case PAIR: + fillSpaces(); + Objects.requireNonNull(value, "TESTBUG: " + element + + "requires a value to be set"); + out.print(value[0] + ": "); + break; + case VALUE: + Objects.requireNonNull(value, "TESTBUG: " + element + + "requires a value to be set"); + out.print(value[0]); + break; + } + stack.push(element); + return this; + } + + private void fillSpaces() { + out.println(); + for (int i = 0; i < spaces; i++) { + // Fill with spaces to be more readable + out.print(" "); + } + } + + /** + * Ends current object or array of {@linkplain Element} + * + * @return this file instance + */ + public JSONFile end() { + if (!stack.empty()) { + Element prev = stack.pop(); + while (prev != Element.OBJECT && prev != Element.ARRAY + && !stack.empty()) { + prev = stack.pop(); + } + switch (prev) { + case OBJECT: + spaces--; + fillSpaces(); + out.print("}"); + break; + case ARRAY: + out.print("]"); + break; + default: + throw new Error("TESTBUG: Incorrect end. " + + "Wrong type found: " + prev); + } + } else { + throw new Error("TESTBUG: Incorrect end. Empty stack"); + } + return this; + } + + /** + * Closes this file + */ + @Override + public void close() { + out.close(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/MultiCommand.java b/hotspot/test/compiler/compilercontrol/share/MultiCommand.java new file mode 100644 index 00000000000..4eac177223b --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/MultiCommand.java @@ -0,0 +1,82 @@ +/* + * 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.compilercontrol.share; + +import compiler.compilercontrol.share.method.MethodDescriptor; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.CommandGenerator; +import compiler.compilercontrol.share.scenario.CompileCommand; +import compiler.compilercontrol.share.scenario.Scenario; +import jdk.test.lib.Utils; + +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.List; + +public class MultiCommand extends AbstractTestBase { + private final List testCases; + + public MultiCommand(List testCases) { + this.testCases = testCases; + } + + /** + * Generates a test containing multiple random commands + * + * @param validOnly shows that all commands should be valid + * @return test instance to run + */ + public static AbstractTestBase generateRandomTest(boolean validOnly) { + CommandGenerator cmdGen = new CommandGenerator(); + List commands = cmdGen.generateCommands(); + List testCases = new ArrayList<>(); + for (Command cmd : commands) { + if (validOnly && cmd == Command.NONEXISTENT) { + // skip invalid command + continue; + } + Executable exec = Utils.getRandomElement(METHODS).first; + MethodDescriptor md; + if (validOnly) { + md = AbstractTestBase.getValidMethodDescriptor(exec); + } else { + md = AbstractTestBase.METHOD_GEN.generateRandomDescriptor(exec); + } + CompileCommand cc = cmdGen.generateCompileCommand(cmd, md, null); + testCases.add(cc); + } + return new MultiCommand(testCases); + } + + @Override + public void test() { + Scenario.Builder builder = Scenario.getBuilder(); + for (CompileCommand cc : testCases) { + cc.print(); + builder.add(cc); + } + Scenario scenario = builder.build(); + scenario.execute(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/SingleCommand.java b/hotspot/test/compiler/compilercontrol/share/SingleCommand.java new file mode 100644 index 00000000000..1ca86054bc5 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/SingleCommand.java @@ -0,0 +1,57 @@ +/* + * 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.compilercontrol.share; + +import compiler.compilercontrol.share.method.MethodDescriptor; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.CommandGenerator; +import compiler.compilercontrol.share.scenario.CompileCommand; +import compiler.compilercontrol.share.scenario.Scenario; +import jdk.test.lib.Utils; + +import java.lang.reflect.Executable; + +public class SingleCommand extends AbstractTestBase { + private final Command command; + private final Scenario.Type type; + + public SingleCommand(Command command, Scenario.Type type) { + this.command = command; + this.type = type; + } + + @Override + public void test() { + Scenario.Builder builder = Scenario.getBuilder(); + Executable exec = Utils.getRandomElement(METHODS).first; + MethodDescriptor md = getValidMethodDescriptor(exec); + CommandGenerator cmdGen = new CommandGenerator(); + CompileCommand compileCommand = cmdGen.generateCompileCommand(command, + md, type); + compileCommand.print(); + builder.add(compileCommand); + Scenario scenario = builder.build(); + scenario.execute(); + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/actions/BaseAction.java b/hotspot/test/compiler/compilercontrol/share/actions/BaseAction.java new file mode 100644 index 00000000000..911c000e7f0 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/actions/BaseAction.java @@ -0,0 +1,123 @@ +/* + * 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.compilercontrol.share.actions; + +import compiler.compilercontrol.share.scenario.State; +import jdk.test.lib.Pair; +import jdk.test.lib.ProcessTools; +import pool.PoolHelper; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.OutputStreamWriter; +import java.io.IOException; +import java.lang.reflect.Executable; +import java.net.InetAddress; +import java.net.Socket; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.stream.Collectors; + +public class BaseAction { + private static final List>> METHODS; + private static final Map METHODS_NAMES; + + static { + METHODS = new PoolHelper().getAllMethods(); + METHODS_NAMES = METHODS.stream().collect(Collectors.toMap( + pair -> pair.first.toGenericString(), + pair -> pair.first)); + } + + public static void main(String[] args) { + if (args.length < 1) { + throw new Error("TESTBUG: requires port as parameter: " + + Arrays.toString(args)); + } + int pid; + try { + pid = ProcessTools.getProcessId(); + } catch (Exception e) { + throw new Error("Could not determine own pid", e); + } + int port = Integer.parseInt(args[0]); + System.out.println("INFO: Client connection port = " + port); + List lines; + try ( + Socket socket = new Socket(InetAddress.getLocalHost(), port); + BufferedReader in = new BufferedReader( + new InputStreamReader(socket.getInputStream())); + PrintWriter out = new PrintWriter( + new OutputStreamWriter(socket.getOutputStream()))) { + // send own pid to execute jcmd if needed + out.println(String.valueOf(pid)); + out.flush(); + lines = in.lines().collect(Collectors.toList()); + } catch (IOException e) { + throw new Error("Error on performing network operation", e); + } + check(decodeMap(lines)); + } + + private static Map decodeMap(List lines) { + if (lines == null || lines.size() == 0) { + throw new Error("TESTBUG: unexpected lines list"); + } + Map stateMap = new HashMap<>(); + int startIndex = 0; + ListIterator iterator = lines.listIterator(); + while (iterator.hasNext()) { + int index = iterator.nextIndex(); + String next = iterator.next(); + switch (next) { + case "{" : + startIndex = index; + break; + case "}" : + // method name goes after { + Executable executable = METHODS_NAMES.get(lines.get( + ++startIndex)); + // state description starts after method + State state = State.fromString(lines.subList(++startIndex, + index).toArray(new String[index - startIndex])); + stateMap.put(executable, state); + break; + } + } + return stateMap; + } + + protected static void check(Map methodStates) { + // Check each method from the pool + METHODS.forEach(pair -> { + Executable x = pair.first; + CompileAction.checkCompiled(x, methodStates.get(x)); + }); + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/actions/CompileAction.java b/hotspot/test/compiler/compilercontrol/share/actions/CompileAction.java new file mode 100644 index 00000000000..9f5cd9046ff --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/actions/CompileAction.java @@ -0,0 +1,108 @@ +/* + * 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.compilercontrol.share.actions; + +import compiler.compilercontrol.share.scenario.State; +import compiler.testlibrary.CompilerUtils; +import jdk.test.lib.Asserts; +import jdk.test.lib.Pair; +import jdk.test.lib.Utils; +import pool.PoolHelper; +import sun.hotspot.WhiteBox; + +import java.lang.reflect.Executable; +import java.util.List; +import java.util.concurrent.Callable; + +public class CompileAction { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final int[] COMP_LEVELS; + private static final List>> METHODS + = new PoolHelper().getAllMethods(); + private static final int EXEC_AMOUNT = 100; + + static { + COMP_LEVELS = CompilerUtils.getAvailableCompilationLevels(); + if (COMP_LEVELS.length == 0) { + throw new Error("TESTBUG: test requires JIT " + + "compiler to be available"); + } + } + + /** + * Checks executable if it could be compiled + * + * @param executable given executable to check + * @param state method compilation state + */ + public static void checkCompiled(Executable executable, + State state) { + int first = COMP_LEVELS[0]; + if (first < 4) { + checkCompilation(executable, first, state.isC1Compilable()); + } + int last = COMP_LEVELS[COMP_LEVELS.length - 1]; + if (last == 4) { + checkCompilation(executable, last, state.isC2Compilable()); + } + } + + private static void checkCompilation(Executable executable, + int level, + boolean expectedCompiled) { + execute(executable); + WHITE_BOX.enqueueMethodForCompilation(executable, level); + Utils.waitForCondition( + () -> { + execute(executable); + return !WHITE_BOX.isMethodQueuedForCompilation(executable); + }, 100L); + execute(executable); + boolean isCompiled = WHITE_BOX.isMethodCompiled(executable); + Asserts.assertEQ(isCompiled, expectedCompiled, + String.format("FAILED: method %s compiled: %b, but should: %b" + + " on required level: %d", executable, isCompiled, + expectedCompiled, level)); + } + + private static void execute(Executable executable) { + Callable callable = getCallableFor(executable); + try { + for (int i = 0; i < EXEC_AMOUNT; i++) { + callable.call(); + } + } catch (Exception e) { + throw new Error("Got exception during execution", e); + } + } + + private static Callable getCallableFor(Executable executable) { + for (Pair> pair : METHODS) { + if (pair.first == executable) { + return pair.second; + } + } + throw new Error("TESTBUG: wrong executable: " + executable); + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/method/MethodGenerator.java b/hotspot/test/compiler/compilercontrol/share/method/MethodGenerator.java index 34435a5408c..1054b975892 100644 --- a/hotspot/test/compiler/compilercontrol/share/method/MethodGenerator.java +++ b/hotspot/test/compiler/compilercontrol/share/method/MethodGenerator.java @@ -123,6 +123,23 @@ public class MethodGenerator { return md; } + /** + * Method descriptor that matches any method. Its full signature is *.* + * + * @param executable executable used to generate descriptor + * @return MethodDescriptor instance + */ + public static MethodDescriptor anyMatchDescriptor(Executable executable) { + MethodDescriptor md = new MethodDescriptor(executable); + Combination patterns = new Combination<>(PatternType.ANY, + PatternType.ANY, PatternType.ANY); + md.aClass.setSeparator(Separator.SLASH); + md.aMethod.setSeparator(Separator.DOT); + md.aSignature.setSeparator(Separator.NONE); + md.setPatterns(patterns); + return md; + } + /** * Generates a list of method patterns from the pool of methods * diff --git a/hotspot/test/compiler/compilercontrol/share/method/SignatureType.java b/hotspot/test/compiler/compilercontrol/share/method/SignatureType.java index 588af8e3131..3639efa971b 100644 --- a/hotspot/test/compiler/compilercontrol/share/method/SignatureType.java +++ b/hotspot/test/compiler/compilercontrol/share/method/SignatureType.java @@ -29,6 +29,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.regex.Pattern; /** * This class represents a signature of the method @@ -66,7 +67,8 @@ public class SignatureType extends MethodElementType { if (element.isEmpty()) { setPattern(MethodDescriptor.PatternType.ANY); } else { - super.setElement(element); + this.element = element; + this.regexp = element; } } @@ -148,4 +150,12 @@ public class SignatureType extends MethodElementType { + patternType); } } + + @Override + public String getRegexp() { + if ("\\(.*\\).*".equals(regexp)) { + return regexp; + } + return Pattern.quote(regexp); + } } diff --git a/hotspot/test/compiler/compilercontrol/share/processors/CommandProcessor.java b/hotspot/test/compiler/compilercontrol/share/processors/CommandProcessor.java new file mode 100644 index 00000000000..bd7e66489af --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/processors/CommandProcessor.java @@ -0,0 +1,62 @@ +/* + * 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.compilercontrol.share.processors; + +import compiler.compilercontrol.share.method.MethodDescriptor; +import compiler.compilercontrol.share.scenario.Command; +import compiler.compilercontrol.share.scenario.CompileCommand; +import jdk.test.lib.OutputAnalyzer; + +import java.util.List; +import java.util.function.Consumer; + +/** + * Checks that output contains a string with commands and full method pattern + */ +public class CommandProcessor implements Consumer { + protected final List commands; + + public CommandProcessor(List commands) { + this.commands = commands; + } + + @Override + public void accept(OutputAnalyzer outputAnalyzer) { + for (CompileCommand command : commands) { + MethodDescriptor methodDescriptor = command.methodDescriptor; + if (methodDescriptor.isValid()) { + Command cmd = command.command; + String method = methodDescriptor.getCanonicalString(); + outputAnalyzer.shouldContain("CompileCommand: " + cmd.name + + " " + method); + outputAnalyzer.shouldNotContain("CompileCommand: An error " + + "occurred during parsing"); + } else { + outputAnalyzer.shouldMatch("(CompileCommand: )" + + "(unrecognized command)|(Bad pattern)|" + + "(An error occurred during parsing)"); + } + } + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/processors/LogProcessor.java b/hotspot/test/compiler/compilercontrol/share/processors/LogProcessor.java new file mode 100644 index 00000000000..a1acd0d907c --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/processors/LogProcessor.java @@ -0,0 +1,133 @@ +/* + * 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.compilercontrol.share.processors; + +import compiler.compilercontrol.share.method.MethodDescriptor; +import compiler.compilercontrol.share.method.MethodGenerator; +import compiler.compilercontrol.share.scenario.State; +import jdk.test.lib.Asserts; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.Pair; +import pool.PoolHelper; + +import java.io.File; +import java.io.FileNotFoundException; +import java.lang.reflect.Executable; +import java.util.List; +import java.util.Map; +import java.util.Scanner; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Log compilation file processor + */ +public class LogProcessor implements Consumer { + public static final String LOG_FILE = "compilation.log"; + private static final String TASK_ELEMENT = "]*>"; + private static final String TASK_DONE_ELEMENT = "]*>"; + private static final String TASK_END_ELEMENT = ""; + private static final String ANY_ELEMENT = "<[^>]*>"; + private static final Pattern METHOD_PATTERN = Pattern.compile( + "method='([^']+)'"); + private final List loggedMethods; + private final List testMethods; + private Scanner scanner = null; + + public LogProcessor(Map states) { + loggedMethods = states.keySet().stream() + .filter(x -> states.get(x).isLog()) + .map(MethodGenerator::logDescriptor) + .map(MethodDescriptor::getString) + .collect(Collectors.toList()); + testMethods = new PoolHelper().getAllMethods() + .stream() + .map(pair -> pair.first) + .map(MethodGenerator::logDescriptor) + .map(MethodDescriptor::getString) + .collect(Collectors.toList()); + } + + @Override + public void accept(OutputAnalyzer outputAnalyzer) { + if (loggedMethods.isEmpty()) { + return; + } + getScanner(); + matchTasks(); + } + + /* + * Gets scanner for log file of the test case + */ + private Scanner getScanner() { + File logFile = new File(LOG_FILE); + try { + scanner = new Scanner(logFile); + } catch (FileNotFoundException e) { + throw new Error("TESTBUG: file not found: " + logFile, e); + } + return scanner; + } + + /* + * Parses for <task method='java.lang.String indexOf (I)I' > + * and finds if there is a compilation log for this task + */ + private void matchTasks() { + String task = scanner.findWithinHorizon(TASK_ELEMENT, 0); + while (task != null) { + String element = scanner.findWithinHorizon(ANY_ELEMENT, 0); + if (Pattern.matches(TASK_DONE_ELEMENT, element) + || Pattern.matches(TASK_END_ELEMENT, element)) { + /* If there is nothing between and + except then compilation log is empty */ + Asserts.assertTrue(matchMethod(task), "Compilation log " + + "expected. Met: " + element); + } + task = scanner.findWithinHorizon(TASK_ELEMENT, 0); + } + } + + // Matches given string to regular expression + private boolean matchMethod(String input) { + Matcher matcher = METHOD_PATTERN.matcher(input); + Asserts.assertTrue(matcher.find(), "Wrong matcher or input"); + // Get method and normalize it + String method = normalize(matcher.group(1)); + // Check that this method matches regexp + return loggedMethods.contains(method) || !testMethods.contains(method); + } + + // Normalize given signature to conform regular expression used in tests + private String normalize(String method) { + return method.replaceAll("\\.", "/") // replace dots in a class string + .replaceFirst(" ", ".") // replace space between class and method + .replaceFirst(" ", "") // remove space between method and signature + .replace("<", "<") + .replace(">", ">"); + } +} diff --git a/hotspot/test/compiler/compilercontrol/share/processors/PrintProcessor.java b/hotspot/test/compiler/compilercontrol/share/processors/PrintProcessor.java new file mode 100644 index 00000000000..dab43495931 --- /dev/null +++ b/hotspot/test/compiler/compilercontrol/share/processors/PrintProcessor.java @@ -0,0 +1,115 @@ +/* + * 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.compilercontrol.share.processors; + +import com.sun.management.HotSpotDiagnosticMXBean; +import compiler.compilercontrol.share.method.MethodDescriptor; +import compiler.compilercontrol.share.method.MethodGenerator; +import compiler.compilercontrol.share.scenario.State; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.Pair; +import pool.PoolHelper; + +import java.lang.management.ManagementFactory; +import java.lang.reflect.Executable; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Process output to find compiled methods assemblies printed by print command + */ +public class PrintProcessor implements Consumer { + /** + * Compiled method string pattern. + * Capturing groups are + * 1. Compiler used to compile this method + * 2. Time stamp + * 3. Compile ID + * 4. Method attributes + * 5. Compilation level + * 6. Method name + */ + private static final Pattern COMPILED_METHOD + = Pattern.compile("Compiled method (?\\(.*\\))[ ]+" + + "(?